[C#] 物件輸出的 JSON 按照 Property Name 排序的兩種方法

2022-02-24

紀錄一下一個之前跟其他廠商合作的需求,簡單的說因為我們常常對接 API 的時候是透過 JSON 

對方不一定是微軟的系統,我們要確定彼此的資料是正確的,很簡單就是直接做 checksum 

但是 JSON 這時候第一層的 Propery Name 如果順序不一樣就將無法用同一個方法進行  checksum

這時候就有一個需求,就是將 輸出的 JSON 給排序,只需要第一層的就可以了。




1. 先介紹一下今天要用的物件 User.cs

using System; using System.Collections.Generic; using System.Text; namespace TestXCRSAUtil { public class User { public string Id { get; set; } public DateTime Birth { get; set; } public decimal Salary { get; set; } public string Memo { get; set; } public List<User> Friends { get; set; } public User() { Friends = new List<User>(); } } }


2. 第一層順序並沒有按照順序寫,我相信大家不會沒事開物件的時候都是按照順序寫的,沒有這麼細節控

這時候我們直接 JSON.net 輸出成 JSON 會長這樣

var user1 = new User { Birth = DateTime.Now, Id = "USER1", Memo = "I am User1", Salary = 1_000_000 }; var user2 = new User { Birth = DateTime.Now, Id = "USER2", Memo = "I am User2", Salary = 2_000_000 }; var user3 = new User { Birth = DateTime.Now, Id = "USER3", Memo = "I am User3", Salary = 3_000_000 }; user1.Friends.Add(user2); user1.Friends.Add(user3); var json = JsonConvert.SerializeObject(user1); Console.WriteLine(json); //{"Id":"USER1","Birth":"2022-02-24T14:04:08.8661027+08:00", //"Salary":1000000.0,"Memo":"I am User1", //"Friends":[{"Id":"USER2","Birth":"2022-02-24T14:04:08.8680447+08:00","Salary":2000000.0,"Memo":"I am User2","Friends":[]},{"Id":"USER3","Birth":"2022-02-24T14:04:08.8680509+08:00","Salary":3000000.0,"Memo":"I am User3","Friends":[]}]}


這裡面並沒有按照順序,只會按照你寫的時候的順序。

3. 方法1 : 先轉成 JObject 後進行排序,這裡面有一行我註解掉了,原因是因為如果你需要針對第二層的話再打開

var test1 = SortPropertiesAlphabetically(JObject.FromObject(user1)); Console.WriteLine(JsonConvert.SerializeObject(test1)); //{"Birth":"2022-02-24T14:04:08.8661027+08:00", //"Friends":[{"Id":"USER2","Birth":"2022-02-24T14:04:08.8680447+08:00","Salary":2000000.0,"Memo":"I am User2","Friends":[]},{"Id":"USER3","Birth":"2022-02-24T14:04:08.8680509+08:00","Salary":3000000.0,"Memo":"I am User3","Friends":[]}], //"Id":"USER1","Memo":"I am User1", //"Salary":1000000.0} private static JObject SortPropertiesAlphabetically(JObject source) { var result = new JObject(); foreach (var property in source.Properties().ToList().OrderBy(p => p.Name)) { var value = property.Value as JObject; if (value != null) { //因為只需要第一層 //所以我將遞迴的地方拿掉 //value = SortPropertiesAlphabetically(value); result.Add(property.Name, value); } else { result.Add(property.Name, property.Value); } } return result; }


4. 方法2: 先轉成 ExpandoObject 排序後再輸出

var expando = new ExpandoObject(); var dictionary = (IDictionary<string, object>)expando; foreach (var property in user1.GetType().GetProperties().OrderBy(x => x.Name)) { dictionary.Add(property.Name, property.GetValue(user1)); } Console.WriteLine("----"); Console.WriteLine(JsonConvert.SerializeObject(dictionary)); //{"Birth":"2022-02-24T14:04:08.8661027+08:00", //"Friends":[{"Id":"USER2","Birth":"2022-02-24T14:04:08.8680447+08:00","Salary":2000000.0,"Memo":"I am User2","Friends":[]},{"Id":"USER3","Birth":"2022-02-24T14:04:08.8680509+08:00","Salary":3000000.0,"Memo":"I am User3","Friends":[]}], //"Id":"USER1","Memo":"I am User1", //"Salary":1000000.0}



這兩種方法都可以只是一個先轉成 JObject 還有一個就是  ExpandoObject 其實概念上不變使用的物件不同。

最近有要用到翻了以前的 code 記錄一下。

reference:

https://stackoverflow.com/questions/3330989/order-of-serialized-fields-using-json-net



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