答客問:多層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
}
這部分有二個問題:
- 同學對 Visual Studio IDE 開發工具不夠熟悉
- 同學缺少 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);
}
就能看到我們能正常接收到 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 都能直接取得,我就不多浪費時間,讓大家去玩玩吧。
VSCode 可以試試看這個套件
回覆刪除https://marketplace.visualstudio.com/items?itemName=quicktype.quicktype