[C#] 使用 NJsonSchema.CodeGeneration.CSharp 製作 JSON Schema + 驗證 JSON

2021-01-15

最近因為使用 Azure Logic Apps 了解到自己有一個技術債,就是 JSON Schema , 所以大概去了解一下,簡單來說就是 有一個東西叫做 JSON Schema 他是一個 JSON 可以用來敘述一份 JSON 是不是符合你所敘述的,簡單來說有點像是以前 XML Schema  或是 XML DTD 的東西..

詳細規則 可以參考這裡 https://json-schema.org/specification.html ,這邊有他的規格書,今天我們要做的範例是,我有一個既有的 JSON,我要如何依照他為藍本製作出一個 JSON Schema ,之後我要透過這份 JSON Schema 來驗證我的 JSON 是不是符合規範,這中間我有用到一個套件 NJsonSchema.CodeGeneration.CSharp ( https://www.nuget.org/packages/NJsonSchema.CodeGeneration.CSharp/ )

1. 我建立物件 Foo 跟 Foo2 進行測試 ,這裡面我故意讓 Age 這屬性 一個是 int 一個是 string , 但是我會使用 Foo 製作成 JSON Schema.

public class Foo { public string Key { get; set; } public string Name { get; set; } public int Age { get; set; } public List<Foo> Friends { get; set; } } public class Foo2 { public string Key { get; set; } public string Name { get; set; } //different int => string public string Age { get; set; } //different public List<dynamic> Friends { get; set; } }

2. 將JSON 製作成 JSON Schema , 這裡面我將一個 JSON 物件 使用 Foo 這物件製作 JSON Schema .

var obj1 = new Foo { Name = "DONMA-FOO", Age = 20, Key = "FOOKEY" }; obj1.Friends = new List<Foo>(); obj1.Friends.Add(new Foo { Name = "DONMA-CHILD", Age = 99, Key = "FOOCHILD" }); var obj2 = new Foo2 { Name = "DONMA-FOO", //Change Age Type Age = "20", Key = "FOOKEY" }; obj2.Friends = new List<dynamic>(); //differnet obj2.Friends.Add(new Foo2 { Name = "DONMA-CHILD1", Age = "20", Key = "FOO2CHILD" }); obj2.Friends.Add(obj1); //differnet obj2.Friends.Add(new Foo2 { Name = "DONMA-CHILD2", Age = "20", Key = "FOO2CHILD" }); var schema = NJsonSchema.JsonSchema.FromSampleJson(JsonConvert.SerializeObject(obj1)); Response.Write(schema.ToJson() + "<hr>");
{ "$schema":"http://json-schema.org/draft-04/schema#", "type":"object", "properties":{ "Key":{ "type":"string" }, "Name":{ "type":"string" }, "Age":{ "type":"integer" }, "Friends":{ "type":"array", "items":{ "$ref":"#/definitions/Friend" } } }, "definitions":{ "Friend":{ "type":"object", "properties":{ "Key":{ "type":"string" }, "Name":{ "type":"string" }, "Age":{ "type":"integer" }, "Friends":{ } } } } }

3. 使用 步驟二得到的 JSON Schema 去驗證 JSON 結構

var res1 = schema.Validate(JsonConvert.SerializeObject(obj1)); foreach (var r in res1) { Response.Write(r.Property + "<br>"); } var res2 = schema.Validate(JsonConvert.SerializeObject(obj2)); foreach (var r in res2) { Response.Write(JsonConvert.SerializeObject(r)+ "<br>"); } /* Result : {"Kind":3,"Property":"Age","Path":"#/Age","HasLineInfo":true,"LineNumber":1,"LinePosition":45,"Schema":{"type":"integer"}} {"Errors":{"NJsonSchema.JsonSchema":[{"Kind":3,"Property":"Age","Path":"#/Friends[0].Age","HasLineInfo":true,"LineNumber":1,"LinePosition":108,"Schema":{"type":"integer"}}]},"Kind":36,"Property":"[0]","Path":"#/Friends[0]","HasLineInfo":true,"LineNumber":1,"LinePosition":58,"Schema":{"$ref":"#/definitions/Friend"}} {"Errors":{"NJsonSchema.JsonSchema":[{"Kind":3,"Property":"Age","Path":"#/Friends[2].Age","HasLineInfo":true,"LineNumber":1,"LinePosition":297,"Schema":{"type":"integer"}}]},"Kind":36,"Property":"[2]","Path":"#/Friends[2]","HasLineInfo":true,"LineNumber":1,"LinePosition":247,"Schema":{"$ref":"#/definitions/Friend"}} */



果然抓到三個錯誤結果,第一個是 Foo2 的 Age 是 string  , 第二個是 Foo2 的 Friends 第一個跟第三個物件不對。

其實概念很簡單,其實這畢竟是一個規範,也很博大精深,找時間我再來好好看看,有遇到雷我在寫文分享。


當麻許的碎念筆記 2014 | Donma Hsu Design.