JSON serialization and deserialization in .NET

近期常用到 AJAX 方式去呼叫後端的 Web Services,資料的傳遞交換均是用 JSON (JavaScript Object Notation),這篇主要是整理一些在 .NET 上序列化 (Serialization)和反序列化 (Deserialization)的小技巧和心得。
對於 JSON 的入門觀念可以參閱 Introducing JSON 或是 syshen's blog 中的 JSON 介紹。JSON 的資料格式簡言之可以看成是 Object 和 Array 的組合;Object 是指用大括號 {} 包起來的 string:value 的組合,如果多組組合的話,中間則是以逗號區隔,例如:{string1:value1, string2:value2, ....}。而 Array 的特徵則是用中括號 [] 包住以逗號區隔的 values。

接下來分別整理一下在 .NET 中對 JSON 做序列化和反序列化的動作。

序列化 (Serialization)
假設情境是,前端的 AJAX 對後端的 Web Service 做了一個呼叫,而我們想要回傳 JSON Data 的話,可以用下列的方式。
var query = from _table in DataContext
    .Table select _table; // obtain data by Linq 

System.Web.Script.Serialization.JavaScriptSerializer serializer 
    = new System.Web.Script.Serialization.JavaScriptSerializer();

List<Dictionary<string, object>> rows 
    = new List<Dictionary<string, object>>();

Dictionary<string, object> row;

foreach (var item in query) { 
    // each object can contains the number of string/value pairs 
    row = new Dictionary<string, object>();
    row.Add("string1", value1);
    row.Add("string2", value2);
}

return serializer.Serialize(rows);
反序列化 (Deserialization)
可能的情境是,後端的 Web Service 接收到前端的資料格式為 JSON 結構,可能是單筆也可能是多筆資料的集合;目前的話 .NET 3.5 以上可以用 DataContractJsonSerializer 類別來處理,或是可以用 Json.NET 做解析,使用上最大的差異在於 Json.NET 在做解析(parse)的時候並不需要事前建立對應的 Mapping-Table,但是 DataContractJsonSerializer 使用上必須對應到強型別的物件上 (strongly managed objects),所以需要事先宣告外,在資料結構上有異動時,還需要連動變更。

DataContractJsonSerializer Class
// before using DataContractJsonSerializer class
// , we need to claim the mapping data-types
[Serializable]
[DataContract]
public class DataObject
{

  [DataMember(Name = "title")]
  // can assign the custom property
  public string Title { get; set; }

  [DataMember(Name = "url")]
  public string URL { get; set; }
}


DataContractJsonSerializer ser 
    = new DataContractJsonSerializer(typeof(DataObject));

MemoryStream ms 
    = new MemoryStream(Encoding.Unicode.GetBytes(jsondata));

DataObject o = ser.ReadObject(ms) as DataObject;
但如果 JSON 內含有多筆的資料要如何處理呢? 例如:[{items:{"title": value, "url": value},{"title2": value, "url2": value}}]
// here we need defined List&lt;DataObject&gt;
[DataContract]
public class DataObjects
{
    [DataMember(Name = "items")]
    public List&lt;DataObject&gt; items { get; set; }
}

DataContractJsonSerializer ser 
    = new DataContractJsonSerializer(typeof(DataObjects));

MemoryStream ms 
    = new MemoryStream(Encoding.Unicode.GetBytes(jsondata));

DataObjects os = ser.ReadObject(ms) as DataObjects;


// loop data
foreach (DataObject o in os.items)
{
    Console.WriteLine(o.Title);
    Console.WriteLine(o.URL);
}
References:
Json.NET
如果是使用 Json.NET 的話,就不需要先宣告對應的型別,相對而言較彈性與簡潔;例如輸入的資料格式為:json = [{},{},{},.....,{}]
JArray a = JArray.Parse(json);
foreach (var item in a)
{
    JObject o = item as JObject;
    // Console.WriteLine((string)o["title"]);
}