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

  .NET 5.0 最近发布了,并带来了许多新特性和性能改进。System.Text.Json 也不例外。我们改进了性能和可靠性,并使熟悉 Newtonsoft.Json 的人更容易采用它。在这篇文章中,我将讨论 System.Text.Json 所取得的进展,以及接下来会发生什么。

获取库

      • 如果你的项目是针对 .NET 5 的,安装 .NET 5,System.Text.Json 是开箱即用的,没有任何其他先决条件。

      • 如果你的项目目标是 .NET Core 3.x 或 .NET Framework,或者如果你正在编写一个 .NET Standard 兼容库,请安装最新的 System.Text.Json NuGet 包。

      • 如果您正在启动一个新的 ASP.NET Core 项目或从 ASP.NET Core 2.2 升级到3.0或5.0,System.Text.Json 是默认的序列化库。

System.Text.Json 是什么

  System.Text.Json 是 .NET 内置的 JSON 序列化库,用于将 .NET 对象类型转换为 JSON 字符串,反之亦然,支持 UTF-8 文本编码。它最初是在 .NET Core 3.0 中添加的。库中的一种流行类型是 JsonSerializer,它为处理 JSON 数据提供最高级的功能。下面是一个简单的例子,如何使用它来序列化和反序列化:

using System;
using System.Text.Json;
​
MyType obj = new() { Message = "Hello World!" };
​
string json = JsonSerializer.Serialize(obj);
Console.WriteLine(json); // {"Message":"Hello World!"}
​
MyType anotherObject = JsonSerializer.Deserialize<MyType>("{"Message":"Hello Again."}");
Console.WriteLine(anotherObject.Message); // "Hello Again."
public class MyType
{
    public string Message { get; set; }
}

为什么是 System.Text.Json ?回顾一下 .NET Core 3.x

  处理 JSON 数据已经成为许多 .NET 应用程序的重要组成部分,在许多情况下,这种格式的使用甚至超过了 XML。然而,.NET 并没有一个很好的内建方法来处理 JSON。相反,用户依赖于 Newtonsoft.Json,它继续很好地服务于 .NET 生态系统。很明显,客户将受益于作为框架一部分的现代 JSON库。因此,我们基于以下考虑构建了一个新的JSON库:

      • 提供高性能 JSON api。我们需要一套新的 JSON api,这些 api 的性能经过了高度的调整,利用了框架中的最新特性,比如 Span<T>,并且可以直接处理 UTF-8,而不需要转换成 UTF-16 字符串。这些方面对  ASP.NET Core 至关重要。其中吞吐量是一个关键需求。我们考虑对 Newtonsoft.Json做出一些改变。但我们认为在不破坏现有 Newtonsoft.Json 用户或影响我们所能达到的性能的前提下,这是不可行的。

      • 删除 ASP.NET Core 的 Newtonsoft.Json 依赖。在.NET Core 3.x之前,ASP.NET Core 依赖于 Newtonsoft.Json。而这提供了 ASP.NET Core和Newtonsoft.Json之间的紧密集成。这也意味着 Newtonsoft.Json 的版本是由底层平台决定的。然而,Newtonsoft.Json 经常更新,应用程序开发人员经常需要使用特定的版本。因此,我们想要删除 ASP.NET Core 3.0 的 Newtonsoft.Json 依赖。这样客户就可以选择使用哪个版本,而不用担心他们可能会意外地破坏底层平台。

  考虑到在 .NET 生态系统中 Newtonsoft.Json 的普遍性,我们不希望将其作为依赖项从 ASP.NET Core 中移除而不提供简单的方法将其添加回序列化机制。这样做的方法如下:

      • 安装 Microsoft.AspNetCore.Mvc.Newtonsoft.Json 包

      • 更新 Startup.ConfigureServices(),调用 AddNewtonsoftJson()

services.AddMvc()
    .AddNewtonsoftJson();

我们在 .NET Core 3.0 中发布了什么

  在 NET Core 3.0 中,我们在 System.Text.Json 中提供了以下类型:

      • JsonSerializer:提供了将 .NET 对象序列化为 JSON 表示以及将 JSON 反序列化为 .NET 对象的功能。

      • ​JsonDocument:提供随机访问功能,用于检查 JSON 值的结构内容,而无需自动实例化数据值。这种类型是不可变的。

      • JsonElement:表示 JsonDocument 中的特定 JSON 值。

      • Utf8JsonWriter:为 UTF-8 编码的 JSON 文本的只向前、非缓存写入提供高性能 API。

      • Utf8JsonReader:为 UTF-8 编码的 JSON 文本的只向前、按令牌处理(token-by-token)提供高性能 API。

  在 System.Text.Json.Serialization 命名空间中,我们使用 JsonSerializer 为特定于序列化和反序列化的高级场景和定制提供了属性和 API。其中流行的是 JsonConverter<T> 类型,它允许用户控制特定类型、属性或字段的序列化和反序列化。

  JsonSerializer 为处理 JSON 数据提供了最高级的功能。由于实现序列化器在持久数据格式和 .NET 对象类型之间进行转换的特性非常广泛,JsonSerializer 正在经历比 JSON 栈中的其他类型更多的开发和接收更多的社区反馈。因此,在这篇文章中,我将主要介绍 JsonSerializer 功能。

  在3.0版本中,JsonSerializer 提供了以下功能:

      • 支持序列化和反序列化扁平的旧CLR对象(POCO)、Primitives 和集合

      • 内置异步序列化和反序列化

      • UTF-8数据的本地处理

      • 不区分大小写的反序列化(以及区分大小写的)

      • 使用 JsonNamingPolicy.CamelCase 的 Camel-case 命名策略

      • 使用 JsonNamingPolicy 指定自定义命名策略

      • 转义的 JSON 数据反序列化

      • 序列化支持可选的最小字符转义

      • 序列化忽略空值

      • 反序列化忽略注释

      • 允许尾随逗号

      • 自定义转换器

      • 使用 [JsonExtensionData] 特性反序列化时捕获额外数据

      • 使用 [JsonIgnore] 属性忽略单个属性

      • 使用 [JsonProperty] 特性指定自定义属性名

  请参阅《JSON serialization and deserialization (marshalling and unmarshalling) in .NET》,了解 System.Text.Json 的功能概述。

System.Text.Json 与 Newtonsoft.Json 的区别

  现在,你可能会问自己,我应该从 Newtonsoft.Json 迁移到 System.Text.Json 吗?正如你可能猜到的那样,答案是:视情况而定。在 .NET Core 3.0 中,System.Text.Json 是 ASP.NET Core 的默认序列化器,因为我们相信它对大多数应用程序来说已经足够好了。但是,如果您通过例如使用 Newtonsoft.Json 的几个特性来大量定制序列化行为,您可能会发现迁移比起只有 POCO 来说更加困难。要了解更多细节,请查看《How to migrate from Newtonsoft.Json to System.Text.Json》。

  System.Text.Json 主要关注性能、安全性和符合标准,因为它是新的 .NET 应用程序的默认 JSON 处理堆栈。它在默认行为上有一些关键的不同,并且不打算与 Newtonsoft.Json 具有相同的特性。对于某些场景,使用 System.Text.Json 没有内置的功能,但是有一些推荐的解决方案。对于其他场景,变通方法是不切实际的。如果您的应用程序依赖于某个缺失的特性,请考虑提交一个问题,以确定是否可以添加对您的场景的支持。

  这并不是说 System.Text.Json 没有特性或灵活性,或者 Newtonsoft.Json 是缓慢的;这只是为了说明不同的设计哲学,以及当功能与性能或灵活性发生冲突时,我们如何解决。我们对 System.Text.Json 的目标提供了一个快速的内置 JSON 堆栈,它平衡了性能、安全性和特性集。每个特性请求都要仔细权衡这些设计原则。这可能意味着与这些原则相一致的新项目可能更容易使用 System.Text.Json。而旧的项目在迁移过程中可能会遇到更多的障碍。然而, Newtonsoft.Json 并没有错。如果你对它满意,你应该继续使用它。

  让我提供两个在可预见的将来我们不打算添加到 System.Text.Json 的特性示例:

      • 通过 System.ComponentModel.TypeConverter 进行类型转换

      • 通过 System.Runtime.Serialization 特性调整序列化行为

  它们都被认为是来自旧序列化栈的遗留系统,支持它们会违背 System.Text.Json 的性能优先架构,因为在启动时附加了基于反射的查找,并且在 System.Text.Json.dll 中增加了更多代码的维护和大小负担。此外,任何暗示违背我们的标准遵循原则的特性,例如允许在反序列化时处理格式不正确的 JSON,都不会被接受。

  我们在设计 System.Text.Json 时考虑到可扩展性。这意味着即使上述特性在 JsonSerializer 中没有本机支持,它们仍然可以从用户提供的配置中得到支持。例如,用户可以使用自定义的 JsonConverter<T> 来编写对 TypeConverters 调用的包装器。我们也在考虑 IContractResolver 和 JsonProperty-like 的机制(来自 Newtonsoft.Json),以允许编程控制设置类型和成员的元数据和序列化逻辑(dotnet/runtime #31257),这将允许自定义对 System.Runtime.Serialization 特性的支持。

  JsonSerializer 支持对 JSON 数据的异步序列化和反序列化作为内置的性能特性。这已经被证明为客户通过编写高可伸缩性、响应性和非阻塞的应用程序提供了重要的价值,Newtonsoft.Json 没有内置的机制来支持异步 JSON 处理。

  UTF-8 编码是网络上信息传输的信息的格式。System.Text.Json 与 Newtonsoft.Json 不同,System.Text.Json API 使用这种编码在本地处理数据,不需要来回转码 UTF-16。在将数据作为输入传递到 System.Text.Json API 之前,调用者也不需要手动对数据进行转码。避免这种代码转换还有助于在处理 JSON 数据时产生更好的性能。请注意,基于字符串(UTF-16)的API也可以方便使用,但会带来转码的成本。

性能

  在 .NET Core 3.0 的开发周期中,我们在博客中讨论了 System.Text.Json 与 Newtonsoft.Json 的性能比较:

场景

速度

内存

Deserialization

快2倍

相等或更低

Serialization

快1.5倍

相等或更低

Document (read-only)

快3-5倍

~Allocation free for sizes < 1 MB

Reader

快2-3倍

~Allocation free (until you materialize values)

Writer

快1.3-1.6倍

~Allocation free

  与任何性能基准测试一样,场景各不相同,总结数字也有细微差别。这篇文章的摘要是这样的:

  主要的目标是性能,我们看到速度能快大约2倍,但这取决于您的场景和负载,所以要确保测量对您来说重要的东西。

  有些人认为这是指 System.Text.Json 总是比 Newtonsoft.Json 快一倍,这不是我们想要的。“取决于你的情况和有效载荷”是关键。

  在 .NET 生态系统中,JsonSerializer 和其他序列化器之间有过多次性能比较。您可能已经注意到,JsonSerializer 并不总是最快的。当我们说性能是主要目标时,您可能会想为什么会这样。在软件中,几乎没有功能可以在不损害其他功能的情况下最大化,因此所有功能都是各个方面之间的权衡。虽然 JSON 序列化的性能对我们来说非常重要,但这并不是我们唯一的目标。其他目标包括安全性、可靠性、标准遵从性和可用性。

  以下是我们在提高性能时所做的一些权衡:

      • 在某些情况下使用类 我们决定将 Utf8JsonWriter 变成一个类。它曾经是一个 ref struct,允许更少的分配和更快的访问我们正在写入的底层。我们将它更改为一个类,以避免开发人员偶然创建写入器的副本(例如,按值将其传递给 helper 方法时),而随后的写入最终覆盖缓冲区中的数据的问题。

      • 验证 我们决定在处理 JSON 数据时验证它,这包括 UTF-8 验证和 JSON 语法验证。这对于启用 JSON 输入通常来自不可信来源的服务器和云场景是必要的。

      • 扩展点 序列化程序能够注册自定义转换器。这些间接的方法,虽然相对便宜,但在一个狭窄的回路中运行时成本很高;有时即使当它们没有被使用时(由于查找)。

.NET 5.0有什么新特性?

新特性

  在 .NET 5.0 中,我们实现了社区中最受欢迎的一些特性,使熟悉 Newtonsoft.Json 的人更容易使用。以下是新增功能的概述:

GitHub Issue

描述

#30820

添加(反)序列化时保存对象引用的机制

#32937

为 HttpClient 和 HttpContent 添加扩展方法,允许(反)序列化 JSON

#30255

支持(反)序列化带引号的数字

#29895

支持使用参数化构造函数反序列化对象

#876

支持(反)序列化字段

#779

支持忽略值类型的默认值default

#30687

支持有条件地忽略属性(always,never,当 null/default 时)

#30524

支持非字符串字典键

#29743

允许使用非公共的属性访问器进行(反)序列化

#34439

为自定义转换器提供处理null的选项

#38539

支持新的 C# 记录类型

#30445

向 JsonSerializerOptions 添加 copy 构造函数

#34626

向接受默认序列化的 JsonSerializerOptions 添加构造函数

#31326

启用 JsonSerializer 在 Xamarin iOS/Android 上工作

  当我们宣布 .NET 5.0 和 .NET 5.0 RC 1时,我们介绍了一些新特性,包括改进了对不可变类型的支持,以及在 JSON 对象图中保留引用。在这一节中,我将再讲几个。

支持(反)序列化带引号的数字

  当 .NET Core 3.0 发布时,默认情况下不支持将数字类型反序列化为 JSON 字符串。解决方案是为每个适用的数字类型添加一个自定义转换器,它将控制类型的序列化和反序列化,并包含处理带引号的数字的逻辑。在 .NET 5 中,我们添加了一个方便的可选特性,以支持序列化和反序列化带引号的数字和命名的浮点字面值(NaN、Infinity 和 -Infinity)。下面是一个使用该特性的示例:

using System;
using System.Text.Json;
using System.Text.Json.Serialization;
​
var options = new JsonSerializerOptions
{
    NumberHandling = JsonNumberHandling.AllowReadingFromString | 
        JsonNumberHandling.WriteAsString
};
​
string json = @"{""NumberOne"":1,""NumberTwo"":""2""}";
​
ClassWithInts @class = JsonSerializer.Deserialize<ClassWithInts>(json, options);
Console.WriteLine(@class.NumberOne); // 1
Console.WriteLine(@class.NumberTwo); // 2
​
json = JsonSerializer.Serialize(@class, options);
Console.WriteLine(json); // @"{""NumberOne"":""1"",""NumberTwo"":""2""}";
public class ClassWithInts
{
    public int NumberOne { get; set; }
    public int NumberTwo { get; set; }
}

  除了全局应用的 JsonSerializerOptions.NumberHandling 选项之外,我们还添加了 JsonNumberHandlingAttribute,它允许指定类型、属性或字段的数字处理设置。

支持忽略值类型的default值

  在 .NET Core 3.x 中序列化时,它只能忽略引用的 null 值或可为空值类型的属性,以及 JsonSerializerOptions.IgnoreNullValues 设置仅适用于整个输入对象图。在 .NET 5 中,我们增加了对不可空值类型(如 int 和 float)忽略默认值的支持。此外,现在可以选择默认时忽略的属性和字段。示例如下:

var options = new JsonSerializerOptions
{
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault
};
​
var obj = new MyClass();
string json = JsonSerializer.Serialize(obj, options);
Console.WriteLine(json); // {"MyBool":false}
public class MyClass
{
    public int MyInt { get; set; }
​
    [JsonIgnore(Condition = JsonIgnoreCondition.Never)]
    public bool MyBool { get; set; }
​
    public string MyString { get; set; }
}

  这里我们看到了新特性的组合:我们告诉序列化器忽略整个对象图的默认值,但指出无论全局选项如何,都不应该忽略其中一个属性。要只忽略空值,而不忽略值类型的默认值,请使用 JsonIgnoreCondition.WhenWritingNull。

  通过这些处理默认值的扩展,JsonSerializerOptions.IgnoreNullValues 属性在即将发布的 .NET 6.0 版本中已经过时。在反序列化和序列化时都执行 IgnoreNullValues 是不需要的,因为没有好理由在输入的有效负载中忽略 null 符号。

JsonSerializerOptions 的实用构造器

  将 JsonSerializerOptions 设置从一个实例复制到另一个实例,然后进行一些更改,这是一种常见的操作。在 .NET 5 中,我们为 JsonSerializerOptions 添加了一个复制构造函数,这使得这个过程更加简单:

JsonSerializerOptions options = new()
{
    NumberHandling = JsonNumberHandling.AllowReadingFromString,
    DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
    Converters = { new JsonStringEnumConverter() }
};
​
JsonSerializerOptions newOptions = new(options)
{
    NumberHandling = JsonNumberHandling.Strict
};
​
Console.WriteLine(newOptions.NumberHandling);
// Strict
Console.WriteLine(newOptions.DefaultIgnoreCondition);
// WhenWritingNull
Console.WriteLine(newOptions.Converters[0]);
// System.Text.Json.Serialization.JsonStringEnumConverter

  在 web 上下文中处理 JSON 数据时,一组常见的选项是使用驼峰命名策略,在反序列化时指定不区分大小写的匹配,并允许读取带引号的数字。新 JsonSerializerDefaults.Web enum 值,以及一个接受 JsonSerializerDefaults 值的新构造函数,提供了一种简单的方法,以一致的方式跨应用程序的多个层重用这些选项(例如,Blazor 场景的客户端、共享和服务器)。让我们一起来看看:

JsonSerializerOptions options = new(JsonSerializerDefaults.Web);
Console.WriteLine(options.PropertyNamingPolicy);
// System.Text.Json.JsonCamelCaseNamingPolicy
Console.WriteLine(options.PropertyNameCaseInsensitive);
// True
Console.WriteLine(options.NumberHandling);
// AllowReadingFromString

  有关 JsonSerializer 支持哪些特性的更多信息,请参阅迁移指南中的该表。

 

性能改善

  在 .NET Core 3.1 和 .NET 5 之间,我们在以下方面改进了性能:

      • 改进了集合的序列化和反序列化性能

      • 改进了小型类型的序列化和反序列化性能

      • 改进了不区分大小写和缺少属性的情况下的反序列化性能

      • 改进了长 JSON 字符串的序列化性能

  这些改进对高性能应用程序尤其有意义。

改进了集合的序列化和反序列化性能

  我们对大型集合进行了显著的改进(反序列化时约1.15x-1.5x,序列化时约1.5x-2.4x)。你可以在 dotnet/runtime #2259 中更详细地看到这些改进。下面的数字显示了处理包含1024个元素的集合的性能数字。

  Dictionary<string, string>

Method
Mean
Error
StdDev
Median
Min
Max
Gen 0
Gen 1
Gen 2
Allocated
Deserialize Before
190.4 us
1.47 us
1.38 us
190.6 us
188.5 us
193.6 us
26.5554
8.3460
163.69 KB
After ~1.2x faster
158.8 us
1.27 us
1.13 us
158.8 us
157.3 us
161.3 us
26.5991
8.8664
164.05 KB
Serialize Before
109.7 us
0.77 us
0.72 us
109.5 us
108.5 us
111.1 us
3.4904
23.92 KB
After ~1.5x faster
74.53 us
0.590 us
0.552 us
74.40 us
73.57 us
75.69 us
3.8179
0.2937
24.17 KB
  List<int>
Method
Mean
Error
StdDev
Median
Min
Max
Gen 0
Gen 1
Gen 2
Allocated
Deserialize Before
76.40 us
0.392 us
0.366 us
76.37 us
75.53 us
76.87 us
1.2169
8.25 KB
After ~1.5x faster
50.05 us
0.251 us
0.235 us
49.94 us
49.76 us
50.43 us
1.3922
8.62 KB
Serialize Before
29.04 us
0.213 us
0.189 us
29.00 us
28.70 us
29.34 us
1.2620
8.07 KB
After ~2.4x faster
12.17 us
0.205 us
0.191 us
12.15 us
11.97 us
12.55 us
1.3187
8.34 KB

改进了小型类型的性能(TechEmpower基准)

  在 .NET 5.0 中,为了提高 .NET 在 TechEmpower JSON 基准测试中的性能,我们做了很大的努力。这项工作涉及多个领域,包括网络堆栈、Kestrel 和 JsonSerializer 本身。结果,当观察在序列化器中完成的工作时,性能现在提高了约19%。
  dotnet/runtime #37976详细介绍了这些变化和性能度量。这里有两组基准。第一个是使用团队维护的JsonSerializer性能基准测试来验证性能。观察到有大约8%的改善。下一部分是 TechEmpower。它衡量了三种不同的方法来满足 TechEmpower JSON 基准测试的需求。SerializeWithCachedBufferAndWriter 是我们在官方基准测试中使用的。
Method
Mean
Error
StdDev
Median
Min
Max
Gen 0
Gen 1
Gen 2
Allocated
SerializeWithCachedBufferAndWriter (Before)
155.3 ns
1.19 ns
1.11 ns
155.5 ns
153.3 ns
157.3 ns
0.0038
24 B
SerializeWithCachedBufferAndWriter (After) ~1.19x faster
130.8 ns
1.50 ns
1.40 ns
130.9 ns
128.6 ns
133.0 ns
0.0037
24 B
  一旦我们将条目更新到 .NET 5.0,所有跨栈完成的工作将会提高 .NET 在 JSON TechEmpower 基准测试中的位置。我们可以在 .NET 3.1 (第19轮,2020-05-28)和 .NET 5.0 (非正式的持续运行,2020-12-14)中比较 aspcore 的性能:
 

  我们可以看到,JSON 序列化的每秒响应数(RPS)从904,846增加到1,190,245,提高了约31%。

改进了不区分大小写和 extra-property 的反序列化性能

  使用 JSON 最常见的一个问题是命名约定与 .NET 设计准则不匹配。JSON 属性通常是 camelCase,.NET 属性和字段通常是 PascalCase。您使用的 JSON 序列化器负责在命名约定之间建立桥梁。这不是免费的,至少在 .NET Core 3.1 中不是。在 .NET 5.0 中,这个成本可以忽略不计。

  允许不区分大小写和额外属性的代码在 .NET 5.0 中得到了极大的改进。在某些情况下,它要快1.75倍。

  下面的基准测试是一个简单的4属性测试类,它的属性名超过7个字符。

  3.1 性能

Method

Mean

Error

StdDev

Median

Min

Max

Gen 0

Gen 1

Gen 2

Allocated

CaseSensitive_Matching

844.2 ns

4.25 ns

3.55 ns

844.2 ns

838.6 ns

850.6 ns

0.0342

224 B

CaseInsensitive_Matching

833.3 ns

3.84 ns

3.40 ns

832.6 ns

829.4 ns

841.1 ns

0.0504

328 B

CaseSensitive_NotMatching (Extra)

1,007.7 ns

9.40 ns

8.79 ns

1,005.1 ns

997.3 ns

1,023.3 ns

0.0722

464 B

CaseInsensitive_NotMatching

1,405.6 ns

8.35 ns

7.40 ns

1,405.1 ns

1,397.1 ns

1,423.6 ns

0.0626

408 B

  5.0 性能

Method

Mean

Error

StdDev

Median

Min

Max

Gen 0

Gen 1

Gen 2

Allocated

CaseSensitive_Matching

799.2 ns

4.59 ns

4.29 ns

801.0 ns

790.5 ns

803.9 ns

0.0985

632 B

CaseInsensitive_Matching

789.2 ns

6.62 ns

5.53 ns

790.3 ns

776.0 ns

794.4 ns

0.1004

632 B

CaseSensitive_NotMatching (Extra)

479.9 ns

0.75 ns

0.59 ns

479.8 ns

479.1 ns

481.0 ns

0.0059

40 B

CaseInsensitive_NotMatching

783.5 ns

3.26 ns

2.89 ns

783.5 ns

779.0 ns

789.2 ns

0.1004

632 B

提高长 JSON 字符串的序列化性能

  dotnet/ corefx# 41845 利用 SSE2 指令来进行安全检查,看看一个 JSON 字符串是否需要转义,速度更快。当序列化常见的有效负载时,有~10-20%的改进。此外,当直接使用写入器写入相对较大的 JSON 字符串时,会有~30%的改进。这个 GitHub 的要点将详细讨论这个更改的性能特征。一个有趣的数据点是,当序列化表示 NuGet 搜索结果的 POCO 实例时,一个基准测试显示了改进:

Method

Mean

Error

StdDev

Median

Min

Max

Gen 0

Gen 1

Gen 2

Allocated

SerializeNugetPayload (Before)

791.7 ms

15.69 ms

16.12 ms

787.4 ms

772.0 ms

827.1 ms

787.3 MB

SerializeNugetPayload (After) ~1.13x faster

698.4 ms

6.63 ms

5.53 ms

699.5 ms

690.9 ms

708.4 ms

787.3 MB

破坏性的变化

  我们在 .NET Core 3.x 到 .NET 5.0 之间做了一些行为上破坏性的改变。鉴于 System.Text.Json 是一个平台组件,遵循一个严格的兼容性标准,就像 .NET 的其他组件一样,这些更改是基于对其影响的仔细评估而做出的,并服务于整个库的改进。尽管这些变化很重要,但它们通常都是针对边缘情况的,尤其是一致性方面,并且对使用库的大多数人的影响应该是最小的。对于更重要的行为改变和新特性的添加,我们让他们选择加入,以避免破坏针对库的以前版本编写的现有代码。检索以下文档查看详细信息:

      • 《Deserialization of char types requires a single-character string》

      • 《ASP.NET Core apps allow deserializing quoted numbers》

      • 《JsonSerializer.Serialize throws ArgumentNullException when Type parameter is null》

      • 《Non-public, parameterless constructors not used for deserialization》

      • 《PropertyNamingPolicy, PropertyNameCaseInsensitive, and Encoder options are honored when serializing and deserializing KeyValuePair<TKey,TValue>》

System.Text.Json 的下一步是什么?

  我们已经开始规划 .NET 6.0。我们将继续处理帮助驱动 System.Text.Json 的最需要的特性。在更多的 .NET 应用程序中,System.Text.Json 是一个可行的 JSON 堆栈选择,权衡每个请求和我们的设计原则。请参阅 dotnet/runtime 43620,了解该建议的概述。下面是一些顶级功能的简介。

用于 JSON 序列化的 C# 源代码生成器(dotnet/runtime #1568)

  投资的一个领域是利用新的 C# 源代码生成器特性来生成代码,这些代码可以在以下方面帮助序列化器:

      • 提高了启动性能

      • 改善运行时吞吐量

      • 减少私有字节的使用

      • ILLinker 由于避免运行时反射而带来的友好性

      • 通过促进 linker 删除序列化器中未使用的基于反射的代码路径和未使用的转换器,从而减少应用程序的大小

  这项工作正在进行中,并处于原型阶段。这项工作的行动项目和进展可以通过 dotnet/runtimelab 的 JSON Code Gen 项目来观察。

  更新后的支持源代码生成的 System.Text.JsonJson 可以通过一个实验性的 NuGet 包来使用。请与我们分享您在使用此功能时观察到的任何性能变化。问题可以在这里用 area-JsonCodeGen 标签记录。

扩展多态的序列化和反序列化(dotnet/runtime #45189)

  多态序列化和反序列化仍然是现代 .NET 应用程序的重要场景。我们希望在 .NET 6.0 中实现的特性可以支持这些场景。

dynamic 和可变的 JSON DOM (dotnet/runtime #45188)

  支持序列化和反序列化 dynamic 类型以及提供可变 JSON 文档是两个密切相关且重要的特性,它们将消除许多客户的阻塞。我们将这些作为 .NET 6.0 潜在的工作项进行跟踪。

杂项改进(dotnet/runtime #45190)

  在 .NET 6.0 中,我们想要做很多其他的特性和改进。一些功能对于 System.Text.Json 将是创新的和独特的。例如支持异步序列化和反序列化的 IAsyncEnumerable<T> 实例(dotnet /运行时# 1570)。其他特性可能更加熟悉,比如添加 snake_case 支持(dotnet/runtime #782),以及能够更改默认的 JsonSerializerOptions 设置(dotnet/runtime #31094)。实现这些特性将会增加 System.Text.Json 的适用性。

写在最后

  .NET 5.0 是 System.Text.Json 的一个重要版本。如果你的项目不是针对 .NET 5.0,你仍然可以通过安装最新的 System.Text.Json NuGet 包来使用。

我们在 .NET 5.0 中做的很多工作都是由社区驱动的。@YohDeadfall 实现了字段支持,并为 JsonSerializer 提供了各种优化。@NikiforovAll 实现了 JsonSerializerOptions 构造函数,该构造函数接受 JsonSerializerDefaults 值。@marcusturewicz 实现了对 JsonDocument 实例的序列化和反序列化的支持。@devsko 在我们发布之前对各种问题做出了修复。@CodeBlanch 修复了 null 和 nullability 问题。@Marusyk 修复了新的 preserve-references 特性中引用相等的错误。@khellang 修复了读取时验证 DateTime 和 DateTimeOffset 有效载荷的错误。@alanisaac, @thomaslevesque, @marcusturewicz, @madmir, @NikiforovAll, @JoshSchreuder, @Jacksondr5 和@KimKiHyuk 贡献了改进 System.Text.Json 测试覆盖率的变更,使其持续接近100%。我们不能在这里强调所有的贡献,但是 .NET 感谢页面向所有的 .NET 运行时贡献者表示了敬意。

  在 .NET 6.0 中,我们将继续进行更多的改进。随着我们的进步, System.Text.Json 将非常受欢迎。只需访问 GitHub 就能查询其现状。如果你有勇气,可以看看那些没有“up-for-grabs”标签的发行。和往常一样,我们非常欢迎反馈,特别是现在我们正在计划下一个版本时。

原文链接

        https://devblogs.microsoft.com/dotnet/whats-next-for-system-text-json/

 

 

posted @ 2022-02-11 12:02  MeteorSeed  阅读(1027)  评论(2编辑  收藏  举报