.NET Core3发布Json API
我們給DNC3(.NET Core 3)上了一個新包,叫做System.Text.Json(點我下載),支持讀寫器,DOM(文檔對象模型),和序列化,在這篇博文里,我會告訴大家為什么要做這個,這個包怎樣工作,你們可以怎么去用它。
也可以看視頻:
https://sec.ch9.ms/ch9/f427/704ea54a-d
獲取新Json庫
面向DNC開發:安裝DNC3的最新預覽版,可獲得新json庫還有ASP.DNC的集成。
面向.NET Standard或DNF開發:安裝這個包(確定nuget允許預覽版,版本需要4.6.0-preview6.19303.8或更高),沒有ASP.DNC的集成。
JSON在DNC3中的前景
Json已經成為了所有現代.NET應用的重要部分,在許多情況下超過了XML的使用數量,但是.NET還沒有一個很好的內建JSON處理方案,在此之前我們一直依靠Json.NET,來為.NET生態服務。
現在我們決定建立一個新的Json庫:
高性能的JSON API。我們需要一批新的Json api,用Span<T>達成高性能,直接處理UTF-8編碼而不用轉碼成UTF-16的字串。兩方面對ASP.DNC都很重要,因為吞吐量非常關鍵。我們考慮過把代碼提交給Json.NET,但是既要達成我們所要的性能,又不破壞Json.NET的客戶使用體驗幾乎是不可能的。用了System.Text.Json,視方案不同可以得到1.3-5倍的性能加速(下面有更多細節),相信還能壓榨出更多性能。
從ASP.DNC中移除Json.NET的依賴。?現在ASP.DNC依賴Json.NET,這樣ASP.DNC和Json.NET的耦合不僅高,還使得Json.NET的版本被平臺所限制。但是Json.NET經常更新,應用開發者經常想要——或者必須使用特定的版本,因此我們打算從ASP.DNC3移除Json.NET的依賴,這樣客戶便可以選擇適用版本,不需要擔心意外崩掉后臺。
為Json.NET提供了一個ASP.DNC的集成包。Json.NET基本變成了.NET處理json的瑞士軍刀。這玩意提供了很多選項和工具,允許客戶便利地處理json需求,我們不想讓客戶體驗打折(原文compromise直譯折中),舉個蠣子,調用AddJsonOptions擴展方法即可在ASP.DNC中配置Json序列化。因此,我們準備對ASP.DNC提供一個Json.NET集成包,開發者可以選擇安裝,這樣他們就可以在新版本中繼續使用Json.NET的好處。我們還需要確保有合適的擴展點,這樣其他組織也可以為他們的Json庫提供類似的集成包。
要查看更多細節和這一舉措跟Json.NET的關系,可以查看我們在去年10月做的討論。
直接使用System.Text.Json
所有的示例都導入了這兩個包:
using System.Text.Json; using System.Text.Json.Serialization;使用序列化
System.Text.Json序列化器可以異步讀寫Json,為UTF-8編碼優化過,使其完美地適應REST API和后臺應用。
class WeatherForecast {public DateTimeOffset Date { get; set; }public int TemperatureC { get; set; }public string Summary { get; set; } }string Serialize(WeatherForecast value) {return JsonSerializer.ToString<WeatherForecast>(value); }默認情況下,我們提供縮小的Json,如果你想提供些人類可讀的東西,可以向序列化器傳入一個JsonSerializerOptions實例,還能配置其他設置,例如處理評論,尾隨逗號和命名策略。
string SerializePrettyPrint(WeatherForecast value) {var options = new JsonSerializerOptions{WriteIndented = true};return JsonSerializer.ToString<WeatherForecast>(value, options); }反序列化與此類似:
// { // "Date": "2013-01-20T00:00:00Z", // "TemperatureC": 42, // "Summary": "Typical summer in Seattle. Not.", // } WeatherForecast Deserialize(string json) {var options = new JsonSerializerOptions{AllowTrailingCommas = true};return JsonSerializer.Parse<WeatherForecast>(json, options); }還支持異步序列化和反序列化:
async Task SerializeAsync(WeatherForecast value, Stream stream) {await JsonSerializer.WriteAsync<WeatherForecast>(value, stream); }你也可以用自定義特性(雖然我更喜歡叫注解)來控制序列化行為,例如忽視Json中的屬性并指定屬性名:
class WeatherForecast {public DateTimeOffset Date { get; set; }// Always in Celsius.[JsonPropertyName("temp")]public int TemperatureC { get; set; }public string Summary { get; set; }// Don't serialize this property.[JsonIgnore]public bool IsHot => TemperatureC >= 30; }目下還不支持F#的特殊行為(例如discriminated unions(可區分聯合)和record types(記錄類型)),以后會加。
使用DOM
有時候你不想反序列化json負載,但是還想將其內容結構化,比方說我們有個溫度集合,打算平均一下星期一的溫度:
[{"date": "2013-01-07T00:00:00Z","temp": 23,},{"date": "2013-01-08T00:00:00Z","temp": 28,},{"date": "2013-01-14T00:00:00Z","temp": 8,}, ]JsonDocument類允許你便捷地訪問每個屬性和對應值。
double ComputeAverageTemperatures(string json) {var options = new JsonReaderOptions{AllowTrailingCommas = true //允許尾隨逗號};using (JsonDocument document = JsonDocument.Parse(json, options)){int sumOfAllTemperatures = 0;int count = 0;foreach (JsonElement element in document.RootElement.EnumerateArray()){DateTimeOffset date = element.GetProperty("date").GetDateTimeOffset();if (date.DayOfWeek == DayOfWeek.Monday){int temp = element.GetProperty("temp").GetInt32();sumOfAllTemperatures += temp;count++;}}var averageTemp = (double)sumOfAllTemperatures / count;return averageTemp;} }使用寫入器
直接可以使用:
var options = new JsonWriterOptions {Indented = true };using (var stream = new MemoryStream()) {using (var writer = new Utf8JsonWriter(stream, options)){writer.WriteStartObject();writer.WriteString("date", DateTimeOffset.UtcNow);writer.WriteNumber("temp", 42);writer.WriteEndObject();}string json = Encoding.UTF8.GetString(stream.ToArray());Console.WriteLine(json); }讀取器需要切換下令牌類型:
byte[] data = Encoding.UTF8.GetBytes(json); Utf8JsonReader reader = new Utf8JsonReader(data, isFinalBlock: true, state: default);while (reader.Read()) {Console.Write(reader.TokenType);switch (reader.TokenType){case JsonTokenType.PropertyName:case JsonTokenType.String:{string text = reader.GetString();Console.Write(" ");Console.Write(text);break;}case JsonTokenType.Number:{int value = reader.GetInt32();Console.Write(" ");Console.Write(value);break;}// Other token types elided for brevity}Console.WriteLine(); }和ASP.DNC的集成
接受或返回對象負載時,ASP.DNC中的大部分Json使用都靠自動序列化,換句話說你的絕大多數應用代碼不知道ASP.DNC用的是哪個Json庫,這樣切換很容易。
在這可以看到在MVC和SignalR中如何啟用新Json庫。
和ASP.DNC MVC的集成
在pre5版本中,ASP.DNC MVC添加了System.Text.Json讀寫json的支持,從pre6開始,新的json庫將成為序列化和反序列化json的默認選項。
用MvcOptions就可以使用序列化器:
services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true);如果你想換回去用Newtonsoft.json,需要:
1.從nuget上安裝它;
2.在ConfigureServices()?添加?AddNewtonsoftJson()?調用:
public void ConfigureServices(IServiceCollection services){...services.AddControllers().AddNewtonsoftJson()...}已知問題
System.Text.Json對OpenAPI / Swagger的支持還在開展,不太可能作為DNC3正式版的一部分發布。
和SignalR的集成
從DNC3Pre5開始,System.Text.Json是SignalR客戶端和服務器的默認核心協議了。如果你想換回Newtonsoft.Json,那么客戶端和服務端都可以這么做:
安裝Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson包.
在客戶端,向HubConnectionBuilder添加AddNewtonsoftJsonProtocol()調用:
3.在服務端,讓AddSignalR()調用AddNewtonsoftJsonProtocol();
services.AddSignalR().AddNewtonsoftJsonProtocol();性能
既然性能推動我們改良特性,那么我們就需要說說新API帶來的高性能。
記住這些測試是基于預覽版的,正式版的數據很可能大不相同,我們仍然在修改會影響性能的默認行為(比如大小寫敏感),注意這些都是微測試,你實際能得到的好處可能會大不一樣,因此如果你很在意性能,確保你自己的檢測能代表你的負載,如果你遇到希望我們進一步優化的方案,請提交bug。
對System.Text.Json和Json.NET進行微測試,生成如下結果:
場景 速度 內存消耗 反序列化 2倍 持平或更低 序列化 1.5倍 持平或更低 文檔 (只讀) 3-5倍 文件<1MB時幾乎無分配 讀取器 2-3倍 幾乎無分配 (在你測試之前) 寫入器 1.3-1.6倍 幾乎無分配對ASP.DNC MVC的System.Text.Json進行測試:
我們寫了個生成數據的ASP.DNC應用,從MVC控制器序列化和反序列化,然后康康負載大小和測量結果(RPS越高越好):
對于最普遍的負載大小,MVC的System.Text.Json在輸入和輸出時以更小的內存占用達到了20%的吞吐量增加。
總結
DNC3正式版會帶上System.Text.Json API,屬于DNC內建的Json支持,包括讀寫器,只讀DOM,序列化和反序列化。一開始的目標是性能,一般可以有超過Json.NET2倍的性能,但是這取決于你的方案和負載,因此需要確保你的重點。
ASP.DNC3添加了System.Text.Json的支持, 默認啟用。
試試System.Text.Json并向我們反饋!
{"happy": "coding!"}
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的.NET Core3发布Json API的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dotNET Core实现分布式环境下的
- 下一篇: asp.net core 使用 sign