首页 > 其他分享 >使用.Net6中的System.Text.Json遇到几个常见问题及解决方案

使用.Net6中的System.Text.Json遇到几个常见问题及解决方案

时间:2024-07-01 10:44:26浏览次数:16  
标签:常见问题 Name Text System Json CrawlTasks User var new

原文链接:https://blog.csdn.net/zls365365/article/details/124162096

前言

以前.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的实现,因为在前端解析的时候可以很清晰的得到一个空对象,而不是装着空对象的数组(有点绕口……

标签:常见问题,Name,Text,System,Json,CrawlTasks,User,var,new
From: https://www.cnblogs.com/Dongmy/p/18277552

相关文章

  • Android系统之System Server大纲
    前言SystemServer是android基本服务的提供者,是android系统运行的最基本需求,所有server运行在一个叫system_process的进程中,system_process进程是androidjava虚拟机跑的第一个进程,从Zygote创建而来,是andorid系统最重要的java虚拟机。可以说,整个android系统的业务都是围绕syste......
  • Windows11系统System.Workflow.Activities.resources.dll文件丢失问题
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个System.Workflow.Activities.resources.dll......
  • Windows11系统System.Windows.Controls.Ribbon.resources.dll文件丢失问题
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个System.Windows.Controls.Ribbon.resources.......
  • Windows11系统System.Windows.dll文件丢失问题
    其实很多用户玩单机游戏或者安装软件的时候就出现过这种问题,如果是新手第一时间会认为是软件或游戏出错了,其实并不是这样,其主要原因就是你电脑系统的该dll文件丢失了或没有安装一些系统软件平台所需要的动态链接库,这时你可以下载这个System.Windows.dll文件(挑选合适的版本文件......
  • Linux进程间的通信方式(一)System V 消息队列
    文章目录前言1.消息队列概念2.消息队列的应用场景3.消息队列接口分类3.1SystemV消息队列3.2POSIX消息队列4.消息队列相关操作函数4.1ftok函数(获取一个key值)4.2msgget函数(根据key值获取一个消息队列操作符)4.3msgctl函数(设置消息队列属性)4.4msgsnd函......
  • 开源语音转文本Speech-to-Text大模型实战之Wav2Vec篇
    前言近年来,语音转文本(Speech-to-Text,STT)技术取得了长足的进步,广泛应用于各种领域,如语音助手、自动字幕生成、智能客服等。本文将详细介绍如何利用开源语音转文本大模型进行实战,从模型选择、环境搭建、模型训练到实际应用,带您一步步实现语音转文本功能。一、模型选择目前,市......
  • 对原生textarea加上:当前输入字数/最大输入字数
    源码:<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width,initial-scale=1.0"><title>TextareaCharacterCounterwithDr......
  • Git 常见问题处理
    Pushfailed:Unabletoaccess'https://github.com/financialfly/lzz.git/':OpenSSLSSL_connect:SSL_ERROR_SYSCALLinconnectiontogithub.com:443因为Git的Http代理的问题,Git支持三种协议:git://、ssh://和http://,本来push的时候应该走ssh隧道的,但是因为设......
  • GBase 8s 通过systemd实现自启动与关闭
    在RHEL7/CENTOS7/SUSE12及最新的Ubuntu等linux发行版本中,均使用systemd进行服务控制管理(ServiceControlManager)。使用systemd,不再需要编写shell脚本程序来控制启动、关闭。以下是通过systemd方式实现GBase8s数据库的自启动与关闭。适用于操作系统:RHEL7/CENTOS7,以及......
  • Winform RichTextBox 获取Text文本中段落及区块
    在C#WinForms应用程序中,RichTextBox控件是一个功能强大的文本编辑控件,支持多种文本格式。如果你需要获取RichTextBox中每一部分的文本,包括段落和不同样式的区块,可以通过以下步骤实现。总体思路是使用RichTextBox的RichTextBox.Find以及RichTextBox.SelectionStart和RichTextBox.......