【譯】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」標籤的發行。和往常一樣,我們非常歡迎反饋,特別是現在我們正在計划下一個版本時。

原文鏈接

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