使用.Net6中的System.Text.Json遇到几个常见问题及解决方案
前言
以前.NetCore是不內(nèi)置JSON庫的,所以大家都用Newtonsoft的JSON庫,而且也確實挺好用的,不過既然官方出了標準庫,那更方便更值得我們多用用,至少不用每次都nuget安裝Newtonsoft.Json庫了。
不過日常開發(fā)使用中會有一些問題,本文記錄一下解決方法,歡迎交流~
(文章末尾包含小彩蛋)
字符編碼問題
默認的 System.Text.Json 序列化的時候會把所有的非 ASCII 的字符進行轉義,這就會導致很多時候我們的一些非 ASCII 的字符就會變成 \uxxxx 這樣的形式,很多場景下并不太友好,我們可以配置字符編碼來解決被轉義的問題。
例子:
var?testObj=new?{Name?=?"測試",Value?=?123 };var?json?=?JsonSerializer.Serialize(testObj); Console.WriteLine(json);輸出
{"Name":"\u6D4B\u8BD5","Value":123}在我們序列化的時候,可以指定一個 JsonSerializeOptions,而這個 JsonSerializeOptions 中有一個 Encoder 我們可以用來配置支持的字符編碼,不支持的就會被轉義,而默認只支持 ASCII 字符。
所以解決方法如下:
var?json?=?JsonSerializer.Serialize(testObj,?new?JsonSerializerOptions() {Encoder?=?JavaScriptEncoder.Create(UnicodeRanges.All) }) Console.WriteLine(json);輸出結果
{"Name":"測試","Value":123}字符轉義問題
對于一些包含 html 標簽的文本即使指定了所有字符集也會被轉義,這是出于安全考慮。如果覺得不需要轉義也可以配置,配置使用 JavaScriptEncoder.UnsafeRelaxedJsonEscaping 即可。
示例代碼
var?testObj?=?new?{Name?=?"測試",Value?=?123,Code?=?"<p>test</p>" };var?json?=?JsonSerializer.Serialize(testObj,?new?JsonSerializerOptions?{Encoder?=?JavaScriptEncoder.Create(UnicodeRanges.All) }); Console.WriteLine(json);輸出
{"Name":"測試","Value":123,"Code":"\u003Cp\u003Etest\u003C/p\u003E"}可以看到HTML代碼被轉義了,這很明顯就不行
解決方法
var?json?=?JsonSerializer.Serialize(testObj,?new?JsonSerializerOptions?{Encoder?=?JavaScriptEncoder.UnsafeRelaxedJsonEscaping });輸出結果
{"Name":"測試","Value":123,"Code":"<p>test</p>"}搞定!
對象套娃遞歸問題
這個問題在我之前的一篇文章中有詳細說到:Asp-Net-Core開發(fā)筆記:接口返回json對象出現(xiàn)套娃遞歸問題
當時我是用Newtonsoft.Json來解決的,不過當我把這篇文章發(fā)布到博客園之后,有大佬指出.NetCore標準庫System.Text.Json中也有解決這個問題的方法,于是我這里也來記錄一下~
首先建立幾個實體類
internal?class?EntityBase?{public?string?Id?{?get;?set;?} } internal?class?CrawlTask?:?EntityBase?{///?<summary>///?爬蟲名稱///?</summary>public?string?Name?{?get;?set;?}///?<summary>///?創(chuàng)建這個爬蟲的用戶///?</summary>public?User?User?{?get;?set;?}///?<summary>///?用戶ID///?</summary>public?string??UserId?{?get;?set;?} } internal?class?User?:?EntityBase?{///?<summary>///?用戶名///?</summary>public?string?Name?{?get;?set;?}///?<summary>///?用戶創(chuàng)建的爬蟲///?</summary>public?List<CrawlTask>?CrawlTasks?{?get;?set;?} }然后用模擬數(shù)據(jù)來重現(xiàn)問題
//模擬數(shù)據(jù) var?crawlTask?=?new?CrawlTask?{?Name?=?"爬蟲名稱",?UserId=?"0f3d4b2f-3b4e-4d08-8f4c-0009a316f041"?}; var?user?=?new?User?{?Name?=?"用戶名",?CrawlTasks?=?new?List<CrawlTask>?{?crawlTask?}?}; crawlTask.User?=?user;//?輸出 var?json2?=?JsonSerializer.Serialize(crawlTask); Console.WriteLine(json2);輸出結果,直接報錯
Unhandled?exception.?System.Text.Json.JsonException:?A?possible?object?cycle?was?detected.?This?can?either?be?due?to?a?cycle?or?if?the?object?depth?is?larger?tha n?the?maximum?allowed?depth?of?64.?Consider?using?ReferenceHandler.Preserve?on?JsonSerializerOptions?to?support?cycles.?Path:?$.User.CrawlTasks.User.CrawlTasks.U ser.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.Us er.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.Name. ...我們都知道了這是對象的套娃遞歸問題了
所以接下來直接上解決方法
var?json2?=?JsonSerializer.Serialize(crawlTask,new?JsonSerializerOptions?{Encoder?=?JavaScriptEncoder.UnsafeRelaxedJsonEscaping,WriteIndented?=?true,ReferenceHandler?=?ReferenceHandler.IgnoreCycles }); Console.WriteLine(json2);ReferenceHandler.IgnoreCycles方式是.Net6新增加的,可以實現(xiàn)和Newtonsoft.Json里ReferenceLoopHandling.Ignore差不多的效果。
最終輸出效果如下
{"Name":?"爬蟲名稱","User":?{"Name":?"用戶名","CrawlTasks":?[null],"Id":?null},"UserId":?"0f3d4b2f-3b4e-4d08-8f4c-0009a316f041","Id":?null }可以看到導致套娃遞歸的屬性變成了null
不過這個和Newtonsoft.Json實現(xiàn)的效果還是有點差異的
在我之前的文章里,Newtonsoft.Json實現(xiàn)的效果是
{"name":?"test?crawl123","user":?{"name":?"string","crawlTasks":?null,"id":?"0f3d4b2f-3b4e-4d08-8f4c-0009a316f041"},"userId":?"0f3d4b2f-3b4e-4d08-8f4c-0009a316f041","id":?"4d52d83b-f3ec-47c6-ab26-e241c09c14d1" }可以看到的是,crawlTask.user.crawlTasks這個屬性有差別,System.Text.Json是一個數(shù)組,然后里面有一個null對象,而Newtonsoft.Json是把這個屬性直接置為null
相比之下,我更喜歡Newtonsoft.Json的實現(xiàn),因為在前端解析的時候可以很清晰的得到一個空對象,而不是裝著空對象的數(shù)組(有點繞口……
后記
說實話,JSON處理還是Python這類動態(tài)語言比較方便
像上面那些問題,Python加個ensure_ascii參數(shù)就行(雖然C#也不難)
比如
import?jsontest_obj?=?{"name":?"測試","value":?123,"code":?"<p>test</p>" } print(json.dumps(test_obj,?ensure_ascii=False))有時我還喜歡加個indent參數(shù),這樣輸出來的JSON字符串更好看
json.dumps(test_obj,?ensure_ascii=False,?indent=2)輸出結果
{"Name":?"測試","Value":?123,"Code":?"<p>test</p>" }總結
以上是生活随笔為你收集整理的使用.Net6中的System.Text.Json遇到几个常见问题及解决方案的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 7. 堪比JMeter的.Net压测工具
- 下一篇: .NET 6 使用 string.Cre