前言

以前.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. 泛型、Junit

    一. 泛型 1.泛型的好处 **1)编译时,检查添加元素的类型,提高了安全2)减少了类西较换的次数,提高效率 不使用泛型Dog -> Object -> Dog //放入到ArrayLis ...

  2. zeppelin安装及配置

    1.下载安装包,zepplin下载地址:http://zeppelin.apache.org/download.html #创建解压目录 mkdir -p /opt/software #解压 tar ...

  3. 【多线程与高并发原理篇:1_cpu多级缓存模型】

    1. 背景 现代计算机技术中,cpu的计算速度远远高于主内存的读写速度.为了解决速度不匹配问题,充分利用cpu的性能,在cpu与主内存之间加入了多级缓存,也叫高速缓存,cpu读取数据直接从高速缓存中读 ...

  4. 《手把手教你》系列技巧篇(六十六)-java+ selenium自动化测试 - 读写excel文件 - 上篇(详细教程)

    1.简介 在自动化测试,有些我们的测试数据是放到excel文件中,尤其是在做数据驱动测试的时候,所以需要懂得如何操作获取excel内的内容.由于java不像python那样有直接操作Excle文件的类 ...

  5. HTML基础笔记整理

    「学习笔记」HTML基础 前言 勤做笔记不仅可以让自己学的扎实,更重要的是可以让自己少走弯路.有人说:"再次翻开笔记是什么感觉",我的回答是:"初恋般的感觉". ...

  6. Solution -「洛谷 P5236」「模板」静态仙人掌

    \(\mathcal{Description}\)   Link.   给定一个 \(n\) 个点 \(m\) 条边的仙人掌,\(q\) 组询问两点最短路.   \(n,q\le10^4\),\(m\ ...

  7. Solution -「JOISC 2021」「LOJ #3489」饮食区

    \(\mathcal{Description}\)   Link.   呐--不想概括题意,自己去读叭~ \(\mathcal{Solution}\)   如果仅有 1. 3. 操作,能不能做?    ...

  8. wmware15安装centos7.9

    详细步骤如下: 下面位置应该写:D:\k8s\k8s-master01 也可以桥接 下面可以删除 从官方下载的,不需要test,所以选择第一个 默认英文的即可 改为上海 保持默认 配置静态ip 主机名 ...

  9. 还在被数据分析报告折磨?Smartbi让你解放双手

    数据分析报告贯穿了企业经营的时时刻刻,方方面面. 数据分析报告最常用于汇报分享:团队需要分享.沟通,数据分析师需要洞察数据.分析结果分享给企业领导.团队同事.大众媒体及更多的利益相关方. 数据分析报告 ...

  10. 【C#异常处理】堆栈溢出

    栈溢出:死循环.递归调用,C# 的堆栈大小对于 32 位进程只有 1 MB,对于 64 位进程只有 4 MB如下: Main(args); static void Main(string[] args ...