System.Text.Json 中的 JsonExtensionData
System.Text.Json 中的 JsonExtensionData
Intro
最近两天在排查我们 API 的一个问题,查看源码过程中发现 System.Text.Json
里有一个有意思的 JsonExtensionData
在反序列化的时候,如果反序列化的 Model 中没有对应的属性信息,这些信息就会丢失,只会保留 Model 里有的数据,而 JsonExtensionData
则可以将这些没有对应属性的信息也保留下来,在序列化的时候也会保留下来。
Sample
直接来看示例吧:
定义的 Model 如下,这里使用了 C# 9 引入的 record
来简化代码
public record Person(string Name, int Age);
如果我们的 JSON 字符串正好只有这两个属性的话
JsonSerializer.Serialize(new{Name = "Ming",Age = 10,});
如果是这样的,那么也不会有什么问题
如果 JSON 字符串会有更多的信息,比如:
JsonSerializer.Serialize(new{Name = "Ming",Age = 10,Title = "SDE",City = "Shanghai"});
可以看到,这个 JSON 会有更多的信息,会包含 Model 里没有定义的 City
和 Title
此时在使用上面的 Model 就会出现信息丢失,Title
和 City
的信息就会丢掉了,System.Text.Json
提供了一种方式 JsonExtensionData
来保存这些在 Model 里没有定义的属性/字段信息
使用 JsonExtensionData
的属性/字段有类型要求,需要是以下三种类型之一:
IDictionary<string, object>
IDictionary<string, JsonElement>
JsonObject
(.NET 6 新增支持)
于是我们就有了下面的测试 Model
public record Person(string Name, int Age);public record Person1(string Name, int Age) : Person(Name, Age)
{[JsonExtensionData]public Dictionary<string, object?> Extensions { get; set; } = new();
}public record Person2(string Name, int Age) : Person(Name, Age)
{[JsonExtensionData]public Dictionary<string, JsonElement> Extensions { get; set; } = new(StringComparer.OrdinalIgnoreCase);
}public record Person3(string Name, int Age) : Person(Name, Age)
{[JsonExtensionData]public JsonObject? Extensions { get; set; }
}
测试代码如下:
var p1 = JsonSerializer.Deserialize<Person1>(jsonString);
ArgumentNullException.ThrowIfNull(p1, nameof(p1));
WriteLine(JsonSerializer.Serialize(p1.Extensions));var p2 = JsonSerializer.Deserialize<Person2>(jsonString);
ArgumentNullException.ThrowIfNull(p2, nameof(p2));
WriteLine(JsonSerializer.Serialize(p2.Extensions));var p3 = JsonSerializer.Deserialize<Person3>(jsonString);
ArgumentNullException.ThrowIfNull(p3, nameof(p3));
WriteLine(JsonSerializer.Serialize(p3.Extensions));
输出结果如下:
可以看到使用了 JsonExtensionData
之后,多余的信息也会保存下来,把 Extensions
打印一下都是一样的结果
Extensions 中保存了我们没有匹配到的信息,这样我们就可以获取到那些可能会丢失掉的数据了
我们可以把整个对象直接打印出来
using static System.Console;var p = JsonSerializer.Deserialize<Person>(jsonString);
ArgumentNullException.ThrowIfNull(p, nameof(p));
WriteLine(JsonSerializer.Serialize(p));var p1 = JsonSerializer.Deserialize<Person1>(jsonString);
ArgumentNullException.ThrowIfNull(p1, nameof(p1));
WriteLine(JsonSerializer.Serialize(p1));var p2 = JsonSerializer.Deserialize<Person2>(jsonString);
ArgumentNullException.ThrowIfNull(p2, nameof(p2));
WriteLine(JsonSerializer.Serialize(p2));var p3 = JsonSerializer.Deserialize<Person3>(jsonString);
ArgumentNullException.ThrowIfNull(p3, nameof(p3));
WriteLine(JsonSerializer.Serialize(p3));
WriteLine(new string('-', 20));
输出结果如下:
More
借助 JsonExtensionData
我们可以实现一些比较灵活的扩展,没有用过的童鞋不妨试一下
细心的童鞋可能会发现最后一个输出的结果会有一些不同,这是一个 BUG 可以参考 issue: https://github.com/dotnet/runtime/issues/60806
上述示例可以在 Github 获取 https://github.com/WeihanLi/SamplesInPractice/blob/master/JsonSample/SystemTextJsonSample/JsonExtensionDataSample.cs
References
https://github.com/WeihanLi/SamplesInPractice/blob/master/JsonSample/SystemTextJsonSample/JsonExtensionDataSample.cs
https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-handle-overflow?WT.mc_id=DT-MVP-5004222
https://docs.microsoft.com/en-us/dotnet/api/system.text.json.serialization.jsonextensiondataattribute?WT.mc_id=DT-MVP-5004222
https://github.com/dotnet/runtime/issues/61080
System.Text.Json 中的 JsonExtensionData相关推荐
- System.Text.Json 中的字符编码
System.Text.Json 中的字符编码 Intro 默认的 System.Text.Json 序列化的时候会把所有的非 ASCII 的字符进行转义,这就会导致很多时候我们的一些非 ASCII ...
- .NET 6 新特性 System.Text.Json 中的 Writeable DOM
.NET 6 新特性 System.Text.Json 中的 Writeable DOM 特性 Intro 在 .NET 6 Preview 4 中,微软加入了 JSON Node 的支持,我们可以动 ...
- System.Text.Json中时间格式化
转自:Rayom cnblogs.com/Rayom/p/13967415.html 简介 .Net Core 3.0开始全新推出了一个名为System.Text.Json的Json解析库,用于序列化 ...
- 使用.Net6中的System.Text.Json遇到几个常见问题及解决方案
前言 以前.NetCore是不内置JSON库的,所以大家都用Newtonsoft的JSON库,而且也确实挺好用的,不过既然官方出了标准库,那更方便更值得我们多用用,至少不用每次都nuget安装Newt ...
- 在.Net Core 3.0中尝试新的System.Text.Json API
.NET Core 3.0提供了一个名为System.Text.Json的全新命名空间,它支持reader/writer,文档对象模型(DOM)和序列化程序.在此博客文章中,我将介绍它如何工作以及如何 ...
- .NET 6 中的七个 System.Text.Json 特性
忽略循环引用 在 .NET 5 中,如果存在循环依赖, 那么序列化的时候会抛出异常, 而在 .NET 6 中, 你可以选择忽略它. Category dotnet = new() {Name = &q ...
- 将$type添加到System.Text.Json序列化中,就像Newtonsoft那样用于动态对象属性
目录 介绍 用户故事5:在System.Text.Json JsonSerializer中支持动态类型 演示项目和测试 修改模型方法 包装方法 总结 Pro Coders团队最近将一个大型项目从New ...
- 接口返回json对象出现套娃递归问题 | System.Text.Json 版本
前言 看到一篇文章<Asp-Net-Core开发笔记:接口返回json对象出现套娃递归问题> 原文是使用 NewtonsoftJson 解决的返回json对象出现套娃递归问题: servi ...
- .NET 6新特性试用 | System.Text.Json序列化代码自动生成
前言 几乎所有.NET序列化程序的实现基础都是反射.下列代码是Newtonsoft.Json的实现: protected virtual JsonProperty CreateProperty(Mem ...
最新文章
- Mac 环境变量配置
- 关于ubuntu终端命令路径太长的问题
- REVERSE-PRACTICE-BUUCTF-6
- C语言课后习题(64)
- Abp vnext Web应用程序开发教程 4 —— 集成测试
- matlab 固态 机械_忆捷固态硬盘怎么样(2款忆捷固态硬盘测评)
- QT 车牌号正则验证
- 手机火狐浏览器怎么开启flash_火狐浏览器flash插件怎么启用?
- Echart饼状图百分比显示
- 恒流源差分放大电路静态分析_多级放大电路以及差分放大电路
- 山西计算机专业三本大学排名,2021山西三本院校排名 最新大学排行榜
- 第一百二十一天 : varnish
- Linux service之自定义服务
- C语言基本变量类型及变量的定义
- jeeplus ani 文档路径
- 在c语言中基本数据类型主要有哪三种,C语言第三讲,基本数据类型
- 十个计算机函数,十个常用函数套路
- Java - 校园类型系统班级升年级
- 数据处理(一):点到直线距离
- Linux下oracle显示问号,oracle数据库显示问号