答客問:多層JSON結構如何轉換為C#的Model物件

答客問:多層JSON結構如何轉換為C#的Model物件

教學上,我一直認為沒有爛問題。只有懂與不懂。

平常我們在課程上設計的範例為求簡單好懂,通常都會盡量簡化。但回去之後的實務問題,在我眼裡都非常有價值。API 的開發可以很簡單,也可以很複雜,例如,只是單純從後端資料庫取資料,資料表與Model的對應關係通常都是一對一(1:1)的,輸出入也很單純只會有一層,除非你導入了如 Entity Framework 之類 ORM,產生了一對多(1:n)或多對多(n:n)的情境。

{
    "filter":{
        "name":"bruce",
        "currentPage":1,
        "pageSize":5
    }
}

以同學提問的情況,感覺比較像 Front-End First(或稱 JSON First),也就是 JSON 規格是由前端定義。我們一步一步來解決。

public class Filter
{
    public string Name { get; set; }
    public int currentPage { get; set; }
    public int pageSize { get; set; }
}

依照提供的資訊,我們設計出類似的 Filter 類別。新增一個測試 API 方法:

[HttpPost]
public IActionResult Post(Filter filter)
{
    return Ok(filter);
}

此時如果前端定義的 JSON 內容透過 PostMan 試打進來,很明顯會收以下有問題 JSON 回應內容:

{
    "name": null,
    "currentPage": 0,
    "pageSize": 0
}

這部分有二個問題:

  1. 同學對 Visual Studio IDE 開發工具不夠熟悉
  2. 同學缺少 JSON to C# 或 C# to JSON 的設計經驗

如果是 JSON First 的開發模式,當我們轉換為 C# 時,其實有現成的工具可以使用。如果是使用 Visual Studio,內建就在轉換工具。

在 Edit → Paste Special → Paste JSON As Classes

以我們取得 JSON 而言,當我們執行 Paste JSON As Classes 會取得以下兩個類別:

public class Rootobject
{
    public Filter filter { get; set; }
}

public class Filter
{
    public string name { get; set; }
    public int currentPage { get; set; }
    public int pageSize { get; set; }
}

Rootobject 是最外層物件,通常會再進行再命名工作,我們重新命名為 FilterModel。它包含了一個含有 Filter 類別的屬性。重新修改我們 API 方法,套用新的 FilterModel

[HttpPost]
public IActionResult Post(FilterModel filter)
{
    return Ok(filter);
}
FilterModel

就能看到我們能正常接收到 JSON 內容了。

那麼如果你是用 Visual Studio Code 之類的開發工具呢?沒關係,線上蠻多這類的轉換工具,例如 json2csharp.com,也是很輕鬆就能取得所需的 C# 類別。

在這種 JSON First 的情境,我非常建議利用工具去轉換。尤其是在對接第三方 API 時,通常你第一時間拿到的就是對方的 JSON 範例,多層次的 JSON 架構,包你轉到眼花,不相信,你可以試試手動轉換以下 Google Map 回傳的 JSON 內容:

{
   "results" : [
      {
         "access_points" : [],
         "address_components" : [
            {
               "long_name" : "5",
               "short_name" : "5",
               "types" : [ "street_number" ]
            },
            {
               "long_name" : "金華街199巷",
               "short_name" : "金華街199巷",
               "types" : [ "route" ]
            },
            {
               "long_name" : "東門",
               "short_name" : "東門",
               "types" : [ "neighborhood", "political" ]
            },
            {
               "long_name" : "大安區",
               "short_name" : "大安區",
               "types" : [ "administrative_area_level_3", "political" ]
            },
            {
               "long_name" : "台北市",
               "short_name" : "台北市",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "台灣",
               "short_name" : "TW",
               "types" : [ "country", "political" ]
            },
            {
               "long_name" : "100",
               "short_name" : "100",
               "types" : [ "postal_code" ]
            }
         ],
         "formatted_address" : "100台灣台北市大安區金華街199巷5號",
         "geometry" : {
            "location" : {
               "lat" : 25.0311803,
               "lng" : 121.5284282
            },
            "location_type" : "ROOFTOP",
            "viewport" : {
               "northeast" : {
                  "lat" : 25.0325292802915,
                  "lng" : 121.5297771802915
               },
               "southwest" : {
                  "lat" : 25.0298313197085,
                  "lng" : 121.5270792197085
               }
            }
         },
         "place_id" : "ChIJ55AeCoOpQjQRN3u86qRMgj8",
         "plus_code" : {
            "compound_code" : "2GJH+F9 台灣台北市大安區永康里",
            "global_code" : "7QQ32GJH+F9"
         },
         "types" : [ "street_address" ]
      }
   ],
   "status" : "OK"
}

答案用線上轉換或 Visual Studio 都能直接取得,我就不多浪費時間,讓大家去玩玩吧。

1 則留言:

  1. VSCode 可以試試看這個套件
    https://marketplace.visualstudio.com/items?itemName=quicktype.quicktype

    回覆刪除

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。