只有累積,沒有奇蹟

2019年9月17日 星期二

[NETCore] 初探 ASP.NET Core 3.0 新朋友 - System.Text.Json

前言
相信大家都發現 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 分鐘,適合上班交通途中觀看使用,小弟不專業的筆記重點整理如下 :

  • MVP (Minimum Viable Product) 概念出發,最小可行性與常用的需求出發來設計 API
  • 目的是提供 高效能的 Json API
  • 使用 .NET Core 2.1 Span<T> 提高性能,與 Json.NET 相比記憶體使用量較低
  • ASP.NET Core 3.0 之後為內建,3.0 之前是使用 Json.NET 
  • 使用 UTF-8 讀取/寫入 Json 文件,( HTTP 使用 UTF-8 編碼,JSON.NET 預設是使用 UTF-16),避免轉碼與記憶體浪費

  • 如有興趣可以直接觀看影片,或是參考黑暗大文章 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  方法,就可以將指定類別序列化的動作
    static void Main(string[] args)
    {
        var comic = new Book()
        {
            ISBN = 9487,
            Name = "One Piece Comic - 934",
            Price = 120
        };
    
        Console.WriteLine(JsonSerializer.Serialize(comic));
    }
    以上代碼輸出 JSON 格式會是
    {"ISBN":9487,"Name":"One Piece Comic - 934","Price":120}
    Serialize 也提供多載的方法,可以透過 JsonSerializerOptions 指定序列化的參數設定,舉例來說上述範例類別序列化後預設會將 JSON 字串進行最小化 minify 動作,因此編排會是一行呈現,若是要取消此設定可以調整 WriteIndented,則可看到較容易閱讀的 JSON 格式
    JsonSerializer.Serialize(comic, new JsonSerializerOptions()
    {
        WriteIndented = true
    })
    序列化的 JSON 格式就會變成如下內容,方便開發者閱讀
    {
      "ISBN": 9487,
      "Name": "One Piece Comic - 934",
      "Price": 120
    }
    更多關於 JsonSerializerOptions 的設定資訊可以參考 MSDN 官方說明文件 : 傳送門 

    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}");
    可以看到輸出結果如下
    ISBN : 9487
    Name : One Piece Comic - 934
    Price: 120
    如果某個物件屬性希望在反序列化時被忽略,可以在屬性加上  [JsonIgore]  attribute 忽略,在反序列化時就不會 bind 該屬性值;或是使用  [JsonPropertyName]  自訂 JSON 屬性名稱可以使用
    public class Book
    {
        [JsonIgnore]
        public int ISBN { get; set; }
        [JsonPropertyName("Name")]
        public string BookName { get; set; }
        public double Price { get; set; }
    }
    輸出如下
    ISBN : 0
    BookName : One Piece Comic - 934
    Price: 120
    另外在序列化與反序列化在 System.Text.Json 都有提供 Async 方法來提高其執行效率

    讀取 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}");
        }
    可以看到輸出結果如下
    Total Price : 666
    另外有時讀取/要轉換的 JSON 的內容可能會多包含一個 "," 符號,這種情境下可以透過 JsonDocumentOptions 設定進行調整,設定其 AllowTrailingCommas 屬性為 true,則可以避免此狀況發生。

    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

    1 則留言:

    1. . These types don't yet support plain old CLR object (POCO) serialization and deserialization.
      這點可能要注意一下

      回覆刪除

    Copyright © m@rcus 學習筆記 | Powered by Blogger

    Design by Anders Noren | Blogger Theme by NewBloggerThemes.com