demoshop

demo, trying to be the best_

當您在自訂 TagHelper 並使用 GetChildContentAsync() 方法來讀取標籤內容時,這是一個常見的應用場景。然而,如果內容中包含特殊符號,可能會遇到問題。因為安全考量,GetChildContentAsync() 方法預設讀取的 HTML 內容是經過編碼的。我曾花費許多時間嘗試將編碼後的文字還原,但始終無法找到解決方法。最終,我意識到我一開始的方向就錯了,因此特別撰寫這篇文章來記錄這次的學習經歷。

情境說明

在我的Blog後台中「參考資料」的設計是設計成一個TextArea,我只需要利用瀏覽器的Copy link as Markdown功能就可以快速的貼上多條的參考連結,每一個連結使用斷行來分隔。

傳到資料庫的內容就會是

[SkillTree](https://skilltree.my)\r\n[twMVC](https://mvc.tw)
[SkillTree](https://skilltree.my)\r\n[twMVC](https://mvc.tw)

前台顯示的時候利用自訂的TagHelper轉換成HTML語法的連結

<markdown-to-html-link>@Model.Source.RefUrl</markdown-to-html-link>
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
    output.TagName = "ul";
    var content = await output.GetChildContentAsync();
            
    var array = content.GetContent().Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
    ...

}

在上面的部分可以看到我使用了Environment.NewLine來作為分割字串,但當我升級到.NET7以後這段Code就壞了,因為預設編碼的問題,所以後端讀到的文字長這樣

問題來源

其中的/r/n被編碼為&#xD;&#xA;所以切割字串失敗導致後方一連串的非預期行為。這時候我的思緒就認為既然你預設編碼(HTML Encoder)了,那我就反編碼(HTML Decoder)就好,於是我找了一堆討論串和文章(以下是從瀏覽器歷史紀錄撈出來的,還有很多沒列出)

解決方式

其中我在微軟官方文件有看到GetChildContentAsync()是可以傳參數的,所以我一直在測試要傳哪種HTML Encoder才能達到我的期望,經歷了一番嘗試,並沒有什麼突破性的發展,突然靈機一動,利用 TagHelper 把Markdown轉HTML我絕對不會是第一個,而Markdown一定有分行符號,所以我轉成這方向去解,找到了這篇文章 Creating an ASP.NET Core Markdown TagHelper and Parser - Rick Strahl's Web Log (west-wind.com)   文章中我注意到了NullHtmlEncoder.Default這個設定,我在苦苦尋找哪個Encoder可以用,卻沒想到有一個NullHtmlEncoder😅,立即修改程式碼如下

public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
    output.TagName = "ul";
    var content = await output.GetChildContentAsync(NullHtmlEncoder.Default);
            
    var array = content.GetContent(NullHtmlEncoder.Default).Split(new[] { Environment.NewLine }, StringSplitOptions.RemoveEmptyEntries);
    ...

}

果然是拿到了未處理的HTML

換行符號被保留下來了

其實這問題根本不是問題,如果一開始我沒有想偏直接往「不要編碼」的路走,根本不會繞那麼大一圈,但這一圈也不是白繞的,查資料的過程對於網頁編碼有了更多的認識,不見得是壞事,順便一題,查資料的過程大量使用 Microsoft Edge 內建的 Copilot 真的是很方便。

回應討論