相信大家都發現 JSON 格式已經取代過去的 XML 成為資料交換的首選,在 ASP.NET Core 3.0 專案範本設定檔也是使用 JSON 作為設定檔的格式,並內建廣受好評的 Json.NET 做為處理 JSON 格式的函式庫,依存放在 Microsoft.AspNetCore.App 無須在透過 Nuget 另外下載,但老牌的 Json.NET 雖然好用但也相對的存在過去一些沉重的包袱,為了提高性能 ASP.NET Core 3.0 Preview 5 開始提供 System.Text.Json namespace 提供多組 API 讓開發者處理 JSON 更為方便,這篇就來簡單 ASP.NET Core 3.0 開始有的新朋友 System.Text.Json API 的基本使用與操作,若有問題或是錯誤的地方歡迎網路的高手大大給予指導。
介紹
使用前可以先參考使用說明書,.NET Blog 文章 : Try the new System.Text.Json APIs 有針對此新的 Json API 做詳細的介紹與說明,除了文章另外好棒棒的提供影片向開發者介紹新朋友的故事
影片內容約 20 分鐘,適合上班交通途中觀看使用,小弟不專業的筆記重點整理如下 :
如有興趣可以直接觀看影片,或是參考黑暗大文章 System.Text.Json! 有更專業詳細的介紹
安裝
使用前需要先透過 nuget 進行下載的動作,因此到 nuget package manager 搜尋並下載 system.text.json
下載過程中會提示安裝後的變更,可以看到目前還是 RC1 階段尚未正式 release
當然也可以透過 Nuget Package Console 輸入下列指令
安裝完畢之後到專案檔底下確認是否有安裝成功
- Install-Package System.Text.Json -Version 4.6.0-rc1.19456.4
- <ItemGroup>
- <PackageReference Include="System.Text.Json" Version="4.6.0-rc1.19456.4" />
- </ItemGroup>
使用
安裝完畢接著可以進行簡單的功能測試,以下就根據目前 System.Text.Json 所提供的功能 Deserialization、Serialize、JsonDocument、JsonTokenType 做基本使用的介紹,在開始前為了方便大家理解建立一個簡單的 book 類別,其中包含 ISBN、Name、Price 三個屬性,方便後續 sample 使用
- public class Book
- {
- public int ISBN { get; set; }
- public string Name { get; set; }
- public double Price { get; set; }
- }
Serialize 序列化
將類別轉為 JSON 字串的過程叫做 序列化,在 System.Text.Json 序列化使用 JsonSerializer.Serialize 方法,就可以將指定類別序列化的動作
以上代碼輸出 JSON 格式會是
- static void Main(string[] args)
- {
- var comic = new Book()
- {
- ISBN = 9487,
- Name = "One Piece Comic - 934",
- Price = 120
- };
- Console.WriteLine(JsonSerializer.Serialize(comic));
- }
Serialize 也提供多載的方法,可以透過 JsonSerializerOptions 指定序列化的參數設定,舉例來說上述範例類別序列化後預設會將 JSON 字串進行最小化 minify 動作,因此編排會是一行呈現,若是要取消此設定可以調整 WriteIndented,則可看到較容易閱讀的 JSON 格式
- {"ISBN":9487,"Name":"One Piece Comic - 934","Price":120}
序列化的 JSON 格式就會變成如下內容,方便開發者閱讀
- JsonSerializer.Serialize(comic, new JsonSerializerOptions()
- {
- WriteIndented = true
- })
更多關於 JsonSerializerOptions 的設定資訊可以參考 MSDN 官方說明文件 : 傳送門
- {
- "ISBN": 9487,
- "Name": "One Piece Comic - 934",
- "Price": 120
- }
Deserialize 反序列化
將字串解析成物件的內容稱為 反序列化,反序列化可以透過 JsonSerializer.Deserialize 方法達到,話不多說直接上 Code
可以看到輸出結果如下
- var jsonString = @"{""ISBN"":9487,""Name"":""One Piece Comic - 934"",""Price"":120}";
- var book = JsonSerializer.Deserialize<Book>(jsonString);
- var comic = new Book()
- {
- ISBN = 9487,
- Name = "One Piece Comic - 934",
- Price = 120
- };
- Console.WriteLine($"ISBN : {book.ISBN}");
- Console.WriteLine($"Name : {book.Name}");
- Console.WriteLine($"Price: {book.Price}");
如果某個物件屬性希望在反序列化時被忽略,可以在屬性加上 [JsonIgore] attribute 忽略,在反序列化時就不會 bind 該屬性值;或是使用 [JsonPropertyName] 自訂 JSON 屬性名稱可以使用
- ISBN : 9487
- Name : One Piece Comic - 934
- Price: 120
輸出如下
- public class Book
- {
- [JsonIgnore]
- public int ISBN { get; set; }
- [JsonPropertyName("Name")]
- public string BookName { get; set; }
- public double Price { get; set; }
- }
另外在序列化與反序列化在 System.Text.Json 都有提供 Async 方法來提高其執行效率
- ISBN : 0
- BookName : One Piece Comic - 934
- Price: 120
讀取 Json Dom - JsonDocument
有時需求是希望讀取 JSON 特定屬性資料,可以透過 JsonDocument 可以輕易的讀取 JSON 屬性與值資訊,以下列例子來說希望取得兩本書的 Price 總和,可以使用 JsonDocument.Parse 讀取 JSON 字串內容,在透過 GetProperty 搜尋要找尋的屬性名稱並轉換為需要的型別,最後在做加總的動作
可以看到輸出結果如下
- static void Main(string[] args)
- {
- var json = @"[
- {
- ""ISBN"": 9487,
- ""Name"": ""One Piece Comic - 934"",
- ""Price"": 120
- },
- {
- ""ISBN"": 5566,
- ""Name"": ""One Piece Comic - 937"",
- ""Price"": 546
- },
- ]";
- using (JsonDocument document = JsonDocument.Parse(json))
- {
- var sumOfAllTemperatures = 0;
- foreach (var element in document.RootElement.EnumerateArray())
- {
- var price = element.GetProperty("Price").GetInt16();
- sumOfAllTemperatures += price;
- }
- Console.WriteLine($"Total Price : {sumOfAllTemperatures}");
- }
另外有時讀取/要轉換的 JSON 的內容可能會多包含一個 "," 符號,這種情境下可以透過 JsonDocumentOptions 設定進行調整,設定其 AllowTrailingCommas 屬性為 true,則可以避免此狀況發生。
- Total Price : 666
WriteJson - Utf8JsonWriter
有讀取 JSON 的 API 當然也提供寫入 JSON 檔案的 API,寫入可以透過 Utf8JsonWriter 方法完成,話不多說直接上 Code,在一開始設定 JSON 格式為好閱讀的排版方式,接著在使用 Utf8JsonWriter 將上面一直提到的 Book 類別結構使用指定型別方式寫入,例如 ISBN 就是使用 WriteNumber、書名使用 WriteString 等內建提供的 API 方法達到需求
可以看到輸出結果如下
- static void Main(string[] args)
- {
- var options = new JsonWriterOptions
- {
- Indented = true
- };
- using (var stream = new MemoryStream())
- {
- using (var writer = new Utf8JsonWriter(stream, options))
- {
- writer.WriteStartObject();
- writer.WriteNumber("ISBN", 9487);
- writer.WriteString("Name", "One Piece Comic - 934");
- writer.WriteNumber("Price", 777);
- writer.WriteEndObject();
- }
- string json = Encoding.UTF8.GetString(stream.ToArray());
- Console.WriteLine(json);
- }
- }
- {
- "ISBN": 9487,
- "Name": "One Piece Comic - 934",
- "Price": 777
- }
感想
這篇文章介紹了在 System.Text.Json 的安裝與使用情境,序列化(Serializer)、反序列化(Deserialize)、JSON 格式的讀 (JsonDocument) 與寫 (Utf8JsonWriter) 的 API 應用,在影片與文章中也有提到 API 將會持續開發中,在文章後面也有提到效能與 Json.NET 至少提升 1.3 ~ 5 倍的速度,但對於 JSON 格式的支援一定不如老牌的 Json.NET 來的齊全,希望在 ASP.NET Core 3.0 正式發布時可以支援更多功能與應用,對開發者來說也是一大家福音 :)
參考
Try the new System.Text.Json APIs
Channel 9 : Try the new System.Text.Json APIs!
SerializerProgrammingModel.md
The future of JSON in .NET Core 3.0
Breaking changes to Microsoft.AspNetCore.App in 3.0
Procesar JSON con System.Text.Json
. These types don't yet support plain old CLR object (POCO) serialization and deserialization.
回覆刪除這點可能要注意一下