前言

以前.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 jsontest_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 6 中的七个 System.Text.Json 特性

    忽略循环引用 在 .NET 5 中,如果存在循环依赖, 那么序列化的时候会抛出异常, 而在 .NET 6 中, 你可以选择忽略它. Category dotnet = new() {Name = &q ...

  2. System.Text.Json 中的 JsonExtensionData

    System.Text.Json 中的 JsonExtensionData Intro 最近两天在排查我们 API 的一个问题,查看源码过程中发现 System.Text.Json 里有一个有意思的 ...

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

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

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

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

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

    译注 尝试新的System.Text.Json API 对于.NET Core 3.0,我们 提供了一个名为System.Text.Json的全新命名空间 ,支持读取器/写入器,文档对象模型(DOM) ...

  6. System.Text.Json 中的字符编码

    System.Text.Json 中的字符编码 Intro 默认的 System.Text.Json 序列化的时候会把所有的非 ASCII 的字符进行转义,这就会导致很多时候我们的一些非 ASCII ...

  7. .NET 6 新特性 System.Text.Json 中的 Writeable DOM

    .NET 6 新特性 System.Text.Json 中的 Writeable DOM 特性 Intro 在 .NET 6 Preview 4 中,微软加入了 JSON Node 的支持,我们可以动 ...

  8. System.Text.Json中时间格式化

    转自:Rayom cnblogs.com/Rayom/p/13967415.html 简介 .Net Core 3.0开始全新推出了一个名为System.Text.Json的Json解析库,用于序列化 ...

  9. 将$type添加到System.Text.Json序列化中,就像Newtonsoft那样用于动态对象属性

    目录 介绍 用户故事5:在System.Text.Json JsonSerializer中支持动态类型 演示项目和测试 修改模型方法 包装方法 总结 Pro Coders团队最近将一个大型项目从New ...

最新文章

  1. gnuplotx轴的logscale显示
  2. windows和ubuntu虚拟机之间不能自由复制粘贴东西(要安装VMware Tools)vmware-install.pl
  3. 【Python】Pandas/Sklearn进行机器学习之特征筛选,有效提升模型性能
  4. python 操作redis,存取为字节格式,避免转码加
  5. Java 的单例模式
  6. [There will be more story......]
  7. python进行对应分析_机器学习算法---对应分析
  8. html中css二级联动,html二级联动学习笔记
  9. 单机rust怎么设置白天_工业除尘器不会选 看看粉尘治理设备生产厂家怎么说
  10. X64_Xcelera-CL_PX4采集卡测试记录
  11. Java中什么是JAP之hibernate-mvc修改功能-Springmvc
  12. 计算机网络——网络安全
  13. Vue 快速原型开发
  14. 分时线的9代表什么_股权生命9条线,持有不同股权代表了什么?
  15. 人脸检测——UnitBox
  16. java swing 文本域_java文本域
  17. 技术分享 | DNS解析不生效的原因及解决方法
  18. linux开篇——硬盘和mbr简介
  19. 【API接口大全】查询订单详情/物流信息/交易订单
  20. 华为南京研究所各部门

热门文章

  1. 原型模式——创建型模式
  2. 设置Windows 8.1屏幕自己主动旋转代码, Auto-rotate function code
  3. 移动web开发(一)——移动web开发必备知识
  4. mysql 不支持 select into
  5. 分析纯文本外链在SEO优化方面的作用
  6. Set函数、Get函数、点语法和类方法
  7. java 高级泛型_Java 泛型高级
  8. Linux禁止用户登录
  9. 【Luogu3931】SAC E#1 - 一道难题 Tree
  10. Mac使用crontab来实现定时任务