使用.Net6中的System.Text.Json遇到几个常见问题及解决方案
前言
以前.NetCore是不内置JSON库的,所以大家都用Newtonsoft
的JSON库,而且也确实挺好用的,不过既然官方出了标准库,那更方便更值得我们多用用,至少不用每次都nuget安装Newtonsoft.Json
库了。
不过日常开发使用中会有一些问题,本文记录一下解决方法,欢迎交流~
(文章末尾包含小彩蛋)
字符编码问题
默认的 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开发笔记:接口返回json对象出现套娃递归问题
当时我是用Newtonsoft.Json
来解决的,不过当我把这篇文章发布到博客园之后,有大佬指出.NetCore
标准库System.Text.Json
中也有解决这个问题的方法,于是我这里也来记录一下~
首先建立几个实体类
internal class EntityBase {
public string Id { get; set; }
}
internal class CrawlTask : EntityBase {
/// <summary>
/// 爬虫名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 创建这个爬虫的用户
/// </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>
/// 用户创建的爬虫
/// </summary>
public List<CrawlTask> CrawlTasks { get; set; }
}
然后用模拟数据来重现问题
//模拟数据
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新增加的,可以实现和Newtonsoft.Json
里ReferenceLoopHandling.Ignore
差不多的效果。
最终输出效果如下
{
"Name": "爬虫名称",
"User": {
"Name": "用户名",
"CrawlTasks": [
null
],
"Id": null
},
"UserId": "0f3d4b2f-3b4e-4d08-8f4c-0009a316f041",
"Id": null
}
可以看到导致套娃递归的属性变成了null
不过这个和Newtonsoft.Json
实现的效果还是有点差异的
在我之前的文章里,Newtonsoft.Json
实现的效果是
{
"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
是一个数组,然后里面有一个null
对象,而Newtonsoft.Json
是把这个属性直接置为null
相比之下,我更喜欢Newtonsoft.Json
的实现,因为在前端解析的时候可以很清晰的得到一个空对象,而不是装着空对象的数组(有点绕口……
后记
说实话,JSON处理还是Python这类动态语言比较方便
像上面那些问题,Python加个ensure_ascii
参数就行(虽然C#也不难)
比如
import json
test_obj = {
"name": "测试",
"value": 123,
"code": "<p>test</p>"
}
print(json.dumps(test_obj, ensure_ascii=False))
有时我还喜欢加个indent
参数,这样输出来的JSON字符串更好看
json.dumps(test_obj, ensure_ascii=False, indent=2)
输出结果
{
"Name": "测试",
"Value": 123,
"Code": "<p>test</p>"
}
使用.Net6中的System.Text.Json遇到几个常见问题及解决方案的更多相关文章
- .net core中关于System.Text.Json的使用
在.Net Framework的时候序列化经常使用Newtonsoft.Json插件来使用,而在.Net Core中自带了System.Text.Json,号称性能更好,今天抽空就来捣鼓一下. 使用起 ...
- 在.Net Core 3.0中尝试新的System.Text.Json API
.NET Core 3.0提供了一个名为System.Text.Json的全新命名空间,它支持reader/writer,文档对象模型(DOM)和序列化程序.在此博客文章中,我将介绍它如何工作以及如何 ...
- [译]试用新的System.Text.Json API
译注 可能有的小伙伴已经知道了,在.NET Core 3.0中微软加入了对JSON的内置支持. 一直以来.NET开发者们已经习惯使用Json.NET这个强大的库来处理JSON. 那么.NET为什么要增 ...
- .NET Core 内置的 System.Text.Json 使用注意
System.Text.Json 是 .NET Core 3.0 新引入的高性能 json 解析.序列化.反序列化类库,武功高强,但毕竟初入江湖,炉火还没纯青,使用时需要注意,以下是我们在实现使用中遇 ...
- .NET Core 3.0 System.Text.Json 和 Newtonsoft.Json 行为不一致问题及解决办法
行为不一致 .NET Core 3.0 新出了个内置的 JSON 库, 全名叫做尼古拉斯 System.Text.Json - 性能更高占用内存更少这都不是事... 对我来说, 很多或大或小的项目能少 ...
- 【译】System.Text.Json 的下一步是什么
.NET 5.0 最近发布了,并带来了许多新特性和性能改进.System.Text.Json 也不例外.我们改进了性能和可靠性,并使熟悉 Newtonsoft.Json 的人更容易采用它.在这篇文章中 ...
- [.Net Core 3.0+/.Net 5] System.Text.Json中时间格式化
简介 .Net Core 3.0开始全新推出了一个名为System.Text.Json的Json解析库,用于序列化和反序列化Json,此库的设计是为了取代Json.Net(Newtonsoft.Jso ...
- .netcore3.0 System.Text.Json 日期格式化
.netcore3.0 的json格式化不再默认使用Newtonsoft.Json,而是使用自带的System.Text.Json来处理. 理由是System.Text.Json 依赖更少,效率更高. ...
- Net core 2.x 升级 3.0 使用自带 System.Text.Json 时区 踩坑经历
.Net Core 3.0 更新的东西很多,这里就不多做解释了,官方和博园大佬写得很详细 关于 Net Core 时区问题,在 2.1 版本的时候,因为用的是 Newtonsoft.Json,配置比较 ...
随机推荐
- 泛型、Junit
一. 泛型 1.泛型的好处 **1)编译时,检查添加元素的类型,提高了安全2)减少了类西较换的次数,提高效率 不使用泛型Dog -> Object -> Dog //放入到ArrayLis ...
- zeppelin安装及配置
1.下载安装包,zepplin下载地址:http://zeppelin.apache.org/download.html #创建解压目录 mkdir -p /opt/software #解压 tar ...
- 【多线程与高并发原理篇:1_cpu多级缓存模型】
1. 背景 现代计算机技术中,cpu的计算速度远远高于主内存的读写速度.为了解决速度不匹配问题,充分利用cpu的性能,在cpu与主内存之间加入了多级缓存,也叫高速缓存,cpu读取数据直接从高速缓存中读 ...
- 《手把手教你》系列技巧篇(六十六)-java+ selenium自动化测试 - 读写excel文件 - 上篇(详细教程)
1.简介 在自动化测试,有些我们的测试数据是放到excel文件中,尤其是在做数据驱动测试的时候,所以需要懂得如何操作获取excel内的内容.由于java不像python那样有直接操作Excle文件的类 ...
- HTML基础笔记整理
「学习笔记」HTML基础 前言 勤做笔记不仅可以让自己学的扎实,更重要的是可以让自己少走弯路.有人说:"再次翻开笔记是什么感觉",我的回答是:"初恋般的感觉". ...
- Solution -「洛谷 P5236」「模板」静态仙人掌
\(\mathcal{Description}\) Link. 给定一个 \(n\) 个点 \(m\) 条边的仙人掌,\(q\) 组询问两点最短路. \(n,q\le10^4\),\(m\ ...
- Solution -「JOISC 2021」「LOJ #3489」饮食区
\(\mathcal{Description}\) Link. 呐--不想概括题意,自己去读叭~ \(\mathcal{Solution}\) 如果仅有 1. 3. 操作,能不能做? ...
- wmware15安装centos7.9
详细步骤如下: 下面位置应该写:D:\k8s\k8s-master01 也可以桥接 下面可以删除 从官方下载的,不需要test,所以选择第一个 默认英文的即可 改为上海 保持默认 配置静态ip 主机名 ...
- 还在被数据分析报告折磨?Smartbi让你解放双手
数据分析报告贯穿了企业经营的时时刻刻,方方面面. 数据分析报告最常用于汇报分享:团队需要分享.沟通,数据分析师需要洞察数据.分析结果分享给企业领导.团队同事.大众媒体及更多的利益相关方. 数据分析报告 ...
- 【C#异常处理】堆栈溢出
栈溢出:死循环.递归调用,C# 的堆栈大小对于 32 位进程只有 1 MB,对于 64 位进程只有 4 MB如下: Main(args); static void Main(string[] args ...