.NET Core3发布Json API
我們給DNC3(.NET Core 3)上了一個新包,叫做System.Text.Json(點我下載),支持讀寫器,DOM(文檔對象模型),和序列化,在這篇博文里,我會告訴大家為什么要做這個,這個包怎樣工作,你們可以怎么去用它。
也可以看視頻:
https://sec.ch9.ms/ch9/f427/704ea54a-d
獲取新Json庫
面向DNC開發(fā):安裝DNC3的最新預(yù)覽版,可獲得新json庫還有ASP.DNC的集成。
面向.NET Standard或DNF開發(fā):安裝這個包(確定nuget允許預(yù)覽版,版本需要4.6.0-preview6.19303.8或更高),沒有ASP.DNC的集成。
JSON在DNC3中的前景
Json已經(jīng)成為了所有現(xiàn)代.NET應(yīng)用的重要部分,在許多情況下超過了XML的使用數(shù)量,但是.NET還沒有一個很好的內(nèi)建JSON處理方案,在此之前我們一直依靠Json.NET,來為.NET生態(tài)服務(wù)。
現(xiàn)在我們決定建立一個新的Json庫:
高性能的JSON API。我們需要一批新的Json api,用Span<T>達(dá)成高性能,直接處理UTF-8編碼而不用轉(zhuǎn)碼成UTF-16的字串。兩方面對ASP.DNC都很重要,因為吞吐量非常關(guān)鍵。我們考慮過把代碼提交給Json.NET,但是既要達(dá)成我們所要的性能,又不破壞Json.NET的客戶使用體驗幾乎是不可能的。用了System.Text.Json,視方案不同可以得到1.3-5倍的性能加速(下面有更多細(xì)節(jié)),相信還能壓榨出更多性能。
從ASP.DNC中移除Json.NET的依賴。?現(xiàn)在ASP.DNC依賴Json.NET,這樣ASP.DNC和Json.NET的耦合不僅高,還使得Json.NET的版本被平臺所限制。但是Json.NET經(jīng)常更新,應(yīng)用開發(fā)者經(jīng)常想要——或者必須使用特定的版本,因此我們打算從ASP.DNC3移除Json.NET的依賴,這樣客戶便可以選擇適用版本,不需要擔(dān)心意外崩掉后臺。
為Json.NET提供了一個ASP.DNC的集成包。Json.NET基本變成了.NET處理json的瑞士軍刀。這玩意提供了很多選項和工具,允許客戶便利地處理json需求,我們不想讓客戶體驗打折(原文compromise直譯折中),舉個蠣子,調(diào)用AddJsonOptions擴(kuò)展方法即可在ASP.DNC中配置Json序列化。因此,我們準(zhǔn)備對ASP.DNC提供一個Json.NET集成包,開發(fā)者可以選擇安裝,這樣他們就可以在新版本中繼續(xù)使用Json.NET的好處。我們還需要確保有合適的擴(kuò)展點,這樣其他組織也可以為他們的Json庫提供類似的集成包。
要查看更多細(xì)節(jié)和這一舉措跟Json.NET的關(guān)系,可以查看我們在去年10月做的討論。
直接使用System.Text.Json
所有的示例都導(dǎo)入了這兩個包:
using System.Text.Json; using System.Text.Json.Serialization;使用序列化
System.Text.Json序列化器可以異步讀寫Json,為UTF-8編碼優(yōu)化過,使其完美地適應(yīng)REST API和后臺應(yīng)用。
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); }默認(rèn)情況下,我們提供縮小的Json,如果你想提供些人類可讀的東西,可以向序列化器傳入一個JsonSerializerOptions實例,還能配置其他設(shè)置,例如處理評論,尾隨逗號和命名策略。
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(可區(qū)分聯(lián)合)和record types(記錄類型)),以后會加。
使用DOM
有時候你不想反序列化json負(fù)載,但是還想將其內(nèi)容結(jié)構(gòu)化,比方說我們有個溫度集合,打算平均一下星期一的溫度:
[{"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類允許你便捷地訪問每個屬性和對應(yīng)值。
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的集成
接受或返回對象負(fù)載時,ASP.DNC中的大部分Json使用都靠自動序列化,換句話說你的絕大多數(shù)應(yīng)用代碼不知道ASP.DNC用的是哪個Json庫,這樣切換很容易。
在這可以看到在MVC和SignalR中如何啟用新Json庫。
和ASP.DNC MVC的集成
在pre5版本中,ASP.DNC MVC添加了System.Text.Json讀寫json的支持,從pre6開始,新的json庫將成為序列化和反序列化json的默認(rèn)選項。
用MvcOptions就可以使用序列化器:
services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.WriteIndented = true);如果你想換回去用Newtonsoft.json,需要:
1.從nuget上安裝它;
2.在ConfigureServices()?添加?AddNewtonsoftJson()?調(diào)用:
public void ConfigureServices(IServiceCollection services){...services.AddControllers().AddNewtonsoftJson()...}已知問題
System.Text.Json對OpenAPI / Swagger的支持還在開展,不太可能作為DNC3正式版的一部分發(fā)布。
和SignalR的集成
從DNC3Pre5開始,System.Text.Json是SignalR客戶端和服務(wù)器的默認(rèn)核心協(xié)議了。如果你想換回Newtonsoft.Json,那么客戶端和服務(wù)端都可以這么做:
安裝Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson包.
在客戶端,向HubConnectionBuilder添加AddNewtonsoftJsonProtocol()調(diào)用:
3.在服務(wù)端,讓AddSignalR()調(diào)用AddNewtonsoftJsonProtocol();
services.AddSignalR().AddNewtonsoftJsonProtocol();性能
既然性能推動我們改良特性,那么我們就需要說說新API帶來的高性能。
記住這些測試是基于預(yù)覽版的,正式版的數(shù)據(jù)很可能大不相同,我們?nèi)匀辉谛薷臅绊懶阅艿哪J(rèn)行為(比如大小寫敏感),注意這些都是微測試,你實際能得到的好處可能會大不一樣,因此如果你很在意性能,確保你自己的檢測能代表你的負(fù)載,如果你遇到希望我們進(jìn)一步優(yōu)化的方案,請?zhí)峤籦ug。
對System.Text.Json和Json.NET進(jìn)行微測試,生成如下結(jié)果:
場景 速度 內(nèi)存消耗 反序列化 2倍 持平或更低 序列化 1.5倍 持平或更低 文檔 (只讀) 3-5倍 文件<1MB時幾乎無分配 讀取器 2-3倍 幾乎無分配 (在你測試之前) 寫入器 1.3-1.6倍 幾乎無分配對ASP.DNC MVC的System.Text.Json進(jìn)行測試:
我們寫了個生成數(shù)據(jù)的ASP.DNC應(yīng)用,從MVC控制器序列化和反序列化,然后康康負(fù)載大小和測量結(jié)果(RPS越高越好):
對于最普遍的負(fù)載大小,MVC的System.Text.Json在輸入和輸出時以更小的內(nèi)存占用達(dá)到了20%的吞吐量增加。
總結(jié)
DNC3正式版會帶上System.Text.Json API,屬于DNC內(nèi)建的Json支持,包括讀寫器,只讀DOM,序列化和反序列化。一開始的目標(biāo)是性能,一般可以有超過Json.NET2倍的性能,但是這取決于你的方案和負(fù)載,因此需要確保你的重點。
ASP.DNC3添加了System.Text.Json的支持, 默認(rèn)啟用。
試試System.Text.Json并向我們反饋!
{"happy": "coding!"}
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的.NET Core3发布Json API的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: dotNET Core实现分布式环境下的
- 下一篇: 认证方案之初步认识JWT