尝试新的 System.Text.Json 源生成器

在 .NET 6.0 的预览版中,我们使用 System.Text.Json 发布了一个新的 C# source generator 来帮助改进应用程序的性能。这里我们将回顾为什么我们要构建它,以及在你的应用程序中可以获得何种优势。

对于 System.Text.Json 源生成器,在 .NET 中,我们现在有一些用于 JSON 序列化的模型可供选择, JsonSerializer 是现有的模型,提供运行时反射支持,另外有两个编译时的源生成模型;这种方式的生成器生成优化后的序列化模型。或者两者都有。在所有的源生成场景中,生成的组件被直接传送给 JsonSerializer 做性能优化。下面是每种序列化模型提供的功能概览。

JsonSerializer JsonSerializer + pre-generatiing optimized serialization login JsonSerializer + pre-generating data access model
Increases serialization throughput No Yes No
Reduces start-up time No Yes Yes
Reduces private memory usage No Yes Yes
Eliminates runtime reflection No Yes Yes
Facilitates trim-safe app size reduction No Yes Yes
Supports all serialization features Yes No Yes

源生成器入门

源生成器可以用于任何 .NET 的 C# 项目,包括控制台应用,类库,Web 应用,以及 Blazor 应用程序。可以通过 System.TExt.Json 的 NuGet 包。在 .NET 6.0 即将到来的预览版 7 中将不再需要。

除了 .NET 6.0,源生成器与其它的 TFM 兼容,即 .NET 5.0 和更低的版本,.NET Framework 和 .NET Standard。API 集在各种 TFM 之间是一致的,但是不同 TFM 的可用的框架 API 不同,内部的实现是不同的。

对 .NET SDK 来说,最低的支持版本是 .NET 5.0

什么是 System.Txt.Json 源生成器

几乎所有的 .NET 序列化器的核心都是反射。反射对于特定场景提供了优异的能力,但是不包括作为高性能云原生应用程序 (特别) 基础的序列化/反序列,以及处理大量的 JSON 文档的场景。对于启动、内存使用和程序集修剪,反射都是问题所在。

一种方案是将运行时反射替换为编译时源生成。源生成器生成 C# 源代码文件,它可以被编译为库或者应用程序的一部分。在编译时生成代码对于 .NET 应用程序可以带来许多优势,包括增强性能。在 .NET 6 中,作为 System.Text.Json 的一部分,我们包括了新的源生成器。JSON 源生成器与 JsonSerializer 协同工作,可以通过多种方式配置。现有的 JsonSerializer 功能不变,所以是否使用新的源生成器是你的选择。JSON 源生成器的工作方式是将 JSON 可序列化类型的运行时检查转换到编译时,它生成一个静态模型来访问这些类型中的数据,直接使用 Utf8JsonWriter 优化序列化逻辑,或者同时使用两者。

为了使用源生成器,你可以定义一个派生于被称为 JsonSerializerContext 的新类型的分部类,使用新的 JsonSerializableAttribute 类来标注可序列化类型。

例如,对于一个简单的 Person 类型进行序列化。

namespace Test
{
internal class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
}

需要为源生成器如下指定类型。

using System.Text.Json.Serialization;

namespace Test
{
[JsonSerializable(typeof(Person))]
internal partial class MyJsonContext : JsonSerializerContext
{
}
}

作为构建过程的一部分,源生成器会将 MyJsonContext 分部类填充为如下类型。

internal partial class MyJsonContext : JsonSerializerContext
{
public static MyJsonContext Default { get; } public JsonTypeInfo<Person> Person { get; } public MyJsonContext(JsonSerializerOptions options) { } public override JsonTypeInfo GetTypeInfo(Type type) => ...;
}

生成的源代码可以通过将它直接传递给 JsonSerializer 的新的重载方法中,以集成到编译的应用程序中。

// 序列化
Person person = new() { FirstName = "Jane", LastName = "Doe" };
byte[] utf8Json = JsonSerializer.SerializeToUtf8Bytes(
person, MyJsonContext.Default.Person); // 反序列化
person = JsonSerializer.Deserialize(utf8Json, MyJsonContext.Default.Person):

为什么使用源生成器?

JsonSerializer 是将 .NET 对象序列化到 JSON 串,以及从 JSON 串反序列回到 .NET 对象的工具。为了处理某种类型,序列化器需要得到如何访问对象成员的信息。在序列化的时候,序列化器需要访问对象的属性和字段读取器。简单来说,在反序列化的时候,序列化器需要访问构造函数来实例化对象,以及对象的字段与属性的设置器。

System.Text.Json 暴露在使用 JsonSerializer 进行序列化和反序列化时影响的机制,通过 JsonSerializerOptions (它支持运行时配置),还可以通过像 [JsonPropertyName(string)] 与 [JsonIgnore] 这样的特性 ( 这支持设计时配置 )。在序列化和反序列化类型的实例的时候,序列化器需要这些配置的信息,以便其使用。

当处理 JSON 可序列化类型的时候,序列化器需要在一个结构中访问关于对象成员和特性的配置信息,优化的格式。我们可以引用此结构化的信息作为必要的序列化元数据来序列化类型。

在以前版本的 System.Text.Json 中,序列化元数据只能在运行时得出,在对每种类型进行第一次序列化和反序列化的时候得出传递给序列化器。在这些元数据生成之后,序列化器执行实际的序列化和反序列化。这里得到的元数据将被缓存并在后继的 JSON 处理中被重用。生成元数据的环节基于反射实现,计算的复杂性在事件和分配上都是昂贵的。我们可以将该阶段称为序列化器的 “热身” 阶段。

System.Text.Json 源生成器帮助我们移除了该热身阶段,通过将运行时中的使用反射的可序列化类型检查转移到编译时进行。检查的结果可以作为源代码,用来初始化结构化的序列化元数据实例。生成器还可以生成高度优化的序列化逻辑,得益于一套 序列特性,指定的预先处理,默认情况下,生成器生成两种类型的源,但是可以配置为仅仅生成一套类型,或者每种可序列化类型一种。

生成的元数据包含在编译生成的程序集中,可以被初始化并直接传递给 JsonSerializer 以便序列化器不需要在运行时生成。这有助于缩减每种类型第一次序列化或者反序列化的时间。使用这些特性,使用该源生成器可以提供如下优势:

  • 增强序列化的吞吐量
  • 缩减启动时间
  • 缩减私有内存的使用
  • 移除对 System.Reflection 和 System.Reflection.Emit 的使用
  • 剪裁兼容的序列化,可以缩减应用程序的尺寸

JsonTypeInfo<T>, JsonTypeInfo, 与JsonSerializerContext 简介

Try the new System.Text.Json source generator | .NET Blog (microsoft.com)

尝试新的 System.Text.Json 源生成器的更多相关文章

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

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

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

    译注 可能有的小伙伴已经知道了,在.NET Core 3.0中微软加入了对JSON的内置支持. 一直以来.NET开发者们已经习惯使用Json.NET这个强大的库来处理JSON. 那么.NET为什么要增 ...

  3. .NET Core 内置的 System.Text.Json 使用注意

    System.Text.Json 是 .NET Core 3.0 新引入的高性能 json 解析.序列化.反序列化类库,武功高强,但毕竟初入江湖,炉火还没纯青,使用时需要注意,以下是我们在实现使用中遇 ...

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

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

  5. [.Net Core 3.0+/.Net 5] System.Text.Json中时间格式化

    简介 .Net Core 3.0开始全新推出了一个名为System.Text.Json的Json解析库,用于序列化和反序列化Json,此库的设计是为了取代Json.Net(Newtonsoft.Jso ...

  6. 【译】System.Text.Json 的下一步是什么

    .NET 5.0 最近发布了,并带来了许多新特性和性能改进.System.Text.Json 也不例外.我们改进了性能和可靠性,并使熟悉 Newtonsoft.Json 的人更容易采用它.在这篇文章中 ...

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

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

  8. 使用System.Text.Json处理Json文档以及部分坑

    System.Text.Json处理Json文档需要用到JsonDocument,JsonElement,JsonProperty. JsonDocument就是一个表示Json文档的东西,JsonE ...

  9. .netcore3.0 System.Text.Json 日期格式化

    .netcore3.0 的json格式化不再默认使用Newtonsoft.Json,而是使用自带的System.Text.Json来处理. 理由是System.Text.Json 依赖更少,效率更高. ...

  10. In .net 4.8,calculate the time cost of serialization in BinaryFormatter,NewtonSoft.json,and System.Text.Json.JsonSerializer.Serialize

    using ConsoleApp390.Model; using Newtonsoft.Json; using System; using System.Collections.Generic; us ...

随机推荐

  1. 全网最适合入门的面向对象编程教程:53 Python 字符串与序列化-字符串与字符编码

    全网最适合入门的面向对象编程教程:53 Python 字符串与序列化-字符串与字符编码 摘要: 在 Python 中,字符串是文本的表示,默认使用 Unicode 编码,这允许你处理各种字符集,字符编 ...

  2. redis - 认识 nosql 认识 redis 基础 linux安装 redis

    sql和nosql的区别 1. 结构化  非结构化 2. 关联的 非关联的 3. sql查询  非 sql 4. 存储方式 磁盘 内存 5.扩展性 垂直 水平 6. 使用场景: 数据结构固定,相关业务 ...

  3. 微宏科技基于 KubeSphere 的微服务架构实践

    作者:尹珉,KubeSphere Ambassador.contributor,KubeSphere 社区用户委员会杭州站站长. 公司简介 杭州微宏科技有限公司于 2012 年成立,专注于业务流程管理 ...

  4. 云原生爱好者周刊:野心很大的云原生数据库 SurrealDB

    开源项目推荐 SurrealDB SurrealDB 是一个开源的端到端云原生数据库,同时支持 Table.Document 和 Graph 等多种数据模型,对外提供 SurrealQL.GraphQ ...

  5. 分享一个很好用的代理转发工具:rinetd

    rinetd介绍: 安装与使用:https://zhuanlan.zhihu.com/p/530875131 注意事项: 1.如果发现配置中的端口在进程中没找到,那就是配置填写错误导致的,笔者就遇到过 ...

  6. Web渗透05_SQL注入(TOP 1漏洞)

    SQL注入是所有WEB漏洞中最危险的攻击方式,带来的危害也是最大的.没有之一. SQL注入基础 在编写web应用时,几乎所有的数据都存储在网站的数据库中,你的账号信息,收藏信息,文章信息等等数据都存在 ...

  7. vue数据异步加载!坑

    "Error in render: "TypeError: Cannot read property '0' of undefined""渲染错误问题 搭建项目 ...

  8. 海外SRC信息收集工具

    海外SRC信息收集 ​ 子域名爆破工具:bbot,subfinder ​ 相关测评:https://blog.blacklanternsecurity.com/p/subdomain-enumerat ...

  9. 3.5 Linux命令行下如何识别文件类型?

    对于第一次使用 Linux 命令行的用户,可能真的搞不清楚哪个是文件,哪个是目录,究其原因是很难直接通过名字看出来目录和文件的区别. 虽然从名称上不容易分辨,但是可以从颜色上进行区分.一般情况下,Li ...

  10. win10本地客户端配置SSL并使用MQTTX

    1.     本地下载Openssl(默认安装即可,最后一个将打赏取消勾选) Win32/Win64 OpenSSL Installer for Windows - Shining Light Pro ...