前言

以前.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.JsonReferenceLoopHandling.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遇到几个常见问题及解决方案的更多相关文章

  1. .net core中关于System.Text.Json的使用

    在.Net Framework的时候序列化经常使用Newtonsoft.Json插件来使用,而在.Net Core中自带了System.Text.Json,号称性能更好,今天抽空就来捣鼓一下. 使用起 ...

  2. 在.Net Core 3.0中尝试新的System.Text.Json API

    .NET Core 3.0提供了一个名为System.Text.Json的全新命名空间,它支持reader/writer,文档对象模型(DOM)和序列化程序.在此博客文章中,我将介绍它如何工作以及如何 ...

  3. [译]试用新的System.Text.Json API

    译注 可能有的小伙伴已经知道了,在.NET Core 3.0中微软加入了对JSON的内置支持. 一直以来.NET开发者们已经习惯使用Json.NET这个强大的库来处理JSON. 那么.NET为什么要增 ...

  4. .NET Core 内置的 System.Text.Json 使用注意

    System.Text.Json 是 .NET Core 3.0 新引入的高性能 json 解析.序列化.反序列化类库,武功高强,但毕竟初入江湖,炉火还没纯青,使用时需要注意,以下是我们在实现使用中遇 ...

  5. .NET Core 3.0 System.Text.Json 和 Newtonsoft.Json 行为不一致问题及解决办法

    行为不一致 .NET Core 3.0 新出了个内置的 JSON 库, 全名叫做尼古拉斯 System.Text.Json - 性能更高占用内存更少这都不是事... 对我来说, 很多或大或小的项目能少 ...

  6. 【译】System.Text.Json 的下一步是什么

    .NET 5.0 最近发布了,并带来了许多新特性和性能改进.System.Text.Json 也不例外.我们改进了性能和可靠性,并使熟悉 Newtonsoft.Json 的人更容易采用它.在这篇文章中 ...

  7. [.Net Core 3.0+/.Net 5] System.Text.Json中时间格式化

    简介 .Net Core 3.0开始全新推出了一个名为System.Text.Json的Json解析库,用于序列化和反序列化Json,此库的设计是为了取代Json.Net(Newtonsoft.Jso ...

  8. .netcore3.0 System.Text.Json 日期格式化

    .netcore3.0 的json格式化不再默认使用Newtonsoft.Json,而是使用自带的System.Text.Json来处理. 理由是System.Text.Json 依赖更少,效率更高. ...

  9. Net core 2.x 升级 3.0 使用自带 System.Text.Json 时区 踩坑经历

    .Net Core 3.0 更新的东西很多,这里就不多做解释了,官方和博园大佬写得很详细 关于 Net Core 时区问题,在 2.1 版本的时候,因为用的是 Newtonsoft.Json,配置比较 ...

随机推荐

  1. HTML与HTTP协议

    HTML与HTTP协议 目录 HTML与HTTP协议 一.HTML 1. HTML概述 2. HTML编辑 3. HTML语法规则 4. HTML文件结构 5. HTML基本标签 (1)头标签中常用标 ...

  2. 手把手教你使用HarmonyOS本地模拟器

    2021年的华为开发者大会(HDC2021)上,我们随DevEco Studio 3.0 Beta1版本发布首次推出了本地模拟器(也称为Local Emulator),支持模拟手机品类. 我们通过下面 ...

  3. CPU平均负载率之stress模拟CPU密集型进程

    一.对CPU密集型进程进行模拟,具体如下: 第一个终端 在第一个终端运行 stress 命令,模拟一个 CPU 使用率 100% 的场景:stress --cpu 1 -- timeout 600 第 ...

  4. IO_FILE——leak 任意读

    在堆题没有show函数时,我们可以用 IO_FILE 进行leak,本文就记录一下如何实现这一手法. 拿一个输出函数 puts 来说,它在源码里的表现形式为 _IO_puts . _IO_puts ( ...

  5. C语言中左值和右值的理解

    左值顾名思义等号左边,右值等号右边. 左值一般指的内存占用的一个符号: 右值指的是常量或者常量表达式: 当然左值也可以通过一些常用的运算符,例如加减乘除/&转化为右值 注意:不是所有的变量都能 ...

  6. 前端点击png透明部分解决方案

    看效果:点击空白区域红色1.点击实体区域红色2.分别得到颜色数据(包括透明度数据),控制台蓝色1.2.根据颜色数据即可解决png透明部分的点击问题. 让图片不能点击,分两种 1. 整张图片不能点击.这 ...

  7. DoS泛洪测试与防御

    实验目的 DoS泛洪测试与防御 实验内容 DoS泛洪测试与防御 实验环境描述 1. 学生机与实验室网络直连: 2. VPC1与实验室网络直连: 3. 学生机与VPC1物理链路连通: 实验步骤 学生登录 ...

  8. RFC2889MAC地址学习速率——网络测试仪实操

    一.简介 RFC 2889为LAN交换设备的基准测试提供了方法学,它将RFC 2544中为网络互联设备基准测试所定义的方法学扩展到了交换设备,提供了交换机转发性能(Forwarding Perform ...

  9. 一文告诉你dashboard究竟有多重要!

    dashboard,我们一看这个词可能会觉得困惑,这是什么意思?看起来很高大上的样子. 实际上它的中文含义即是我们BI界老生常谈的话题--仪表盘.dashboard是商业智能仪表盘的简称,它是一般商业 ...

  10. 不知道这10个术语,你还敢说会JavaScript?

    每个行业,都有业内"行话",不了解这些行话的人,很难融入到行业中,也永远装不了逼. 从Curry到Closes,有很多JavaScript行话(该领域中使用的特殊词汇)知道这些行话 ...