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 里没有定义的 CityTitle

此时在使用上面的 Model 就会出现信息丢失,TitleCity 的信息就会丢掉了,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));

输出结果如下:

output

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相关推荐

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

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

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

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

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

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

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

    前言 以前.NetCore是不内置JSON库的,所以大家都用Newtonsoft的JSON库,而且也确实挺好用的,不过既然官方出了标准库,那更方便更值得我们多用用,至少不用每次都nuget安装Newt ...

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

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

  6. .NET 6 中的七个 System.Text.Json 特性

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

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

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

  8. 接口返回json对象出现套娃递归问题 | System.Text.Json 版本

    前言 看到一篇文章<Asp-Net-Core开发笔记:接口返回json对象出现套娃递归问题> 原文是使用 NewtonsoftJson 解决的返回json对象出现套娃递归问题: servi ...

  9. .NET 6新特性试用 | System.Text.Json序列化代码自动生成

    前言 几乎所有.NET序列化程序的实现基础都是反射.下列代码是Newtonsoft.Json的实现: protected virtual JsonProperty CreateProperty(Mem ...

最新文章

  1. Mac 环境变量配置
  2. 关于ubuntu终端命令路径太长的问题
  3. REVERSE-PRACTICE-BUUCTF-6
  4. C语言课后习题(64)
  5. Abp vnext Web应用程序开发教程 4 —— 集成测试
  6. matlab 固态 机械_忆捷固态硬盘怎么样(2款忆捷固态硬盘测评)
  7. QT 车牌号正则验证
  8. 手机火狐浏览器怎么开启flash_火狐浏览器flash插件怎么启用?
  9. Echart饼状图百分比显示
  10. 恒流源差分放大电路静态分析_多级放大电路以及差分放大电路
  11. 山西计算机专业三本大学排名,2021山西三本院校排名 最新大学排行榜
  12. 第一百二十一天 : varnish
  13. Linux service之自定义服务
  14. C语言基本变量类型及变量的定义
  15. jeeplus ani 文档路径
  16. 在c语言中基本数据类型主要有哪三种,C语言第三讲,基本数据类型
  17. 十个计算机函数,十个常用函数套路
  18. Java - 校园类型系统班级升年级
  19. 数据处理(一):点到直线距离
  20. Linux下oracle显示问号,oracle数据库显示问号

热门文章

  1. 全球增长最快域名解析商Top10:中国占据四席
  2. 转:编写高效的Android代码
  3. ASP 缩略图 (纠错版)
  4. 洛谷 P1736 创意吃鱼法(多维DP)
  5. vim(三)golang代码跳转配
  6. Mysql读写分离php脚本
  7. Html5学习笔记1 元素 标签 属性
  8. PHP实现各种经典算法
  9. 二叉树结构 codevs 1029 遍历问题
  10. 检查点(Checkpoint)过程如何处理未提交的事务