之前在文章裡提過.NET內建兩種JSON轉換工具: JavaScriptSerializer及DataContractJsonSerializer。不過,它們都基於一個假設--"JSON轉換對象是事先已知的Class"!

在某些狀況下,前端所傳回的JSON字串是開發階段無法完全掌握的。

舉個極端的例子。在Javascript裡可用以下寫法搞出一個你做夢都想不到的物件,轉成JSON傳到後端:

var o = {};
for (var i = 0; i < 10; i++)
    o["Prop" + Math.floor(Math.random() * 100000)] = i;
var jsonString = JSON.stringify(o);

遇到這種機車需求,難道Server端就束手無策了嗎?

Thanks God, We have JSON.NET!! 一個極為出色的Open Source JSON解決方案,提供了如同JavaScriptSerializer序列化及反序列化JSON字串的功能,甚至支援LINQ式操作,最重要的是它可透過JObject的物件模型支援"動態物件",解決類別屬性不固定的問題。

以下是簡單的動態物件應用示範: (JSON.NET有親切易讀的說明文件,對Open Source Project來說十分難得,不可錯過了)

using System;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
 
public partial class DynamicJson : System.Web.UI.Page
{
    public class Member
    {
        public string Name;
        public DateTime Birthday;
        public int Level;
        public int[] Records;
    }
 
    protected void Page_Load(object sender, EventArgs e)
    {
        //使用傳統的強型別直接轉換
        Member jeffrey = new Member()
        {
            Name = "Jeffrey",
            Birthday = new DateTime(1990, 1, 1),
            Level = 99,
            Records = new int[] { 1024, 9999, 32767 }
        };
        //(哇塞! 我被序列化了)
        Response.Write(
            JsonConvert.SerializeObject(jeffrey));
        Response.Write("<hr />");
        
        //動態產生Json的範例
        JObject jo = new JObject();
        jo.Add(new JProperty("Name", "Jeffrey"));
        jo.Add(new JProperty("Birthday", new DateTime(1990, 1, 1)));
        jo.Add(new JProperty("Level", 99));
        JArray ja = new JArray();
        ja.Add(new JValue(1024));
        ja.Add(new JValue(9999));
        ja.Add(new JValue(32767));
        jo.Add(new JProperty("Records", ja));
        Response.Write(JsonConvert.SerializeObject(jo));
        Response.Write("<hr />");
 
        //也可以像XDocument一樣一次宣告
        jo = new JObject(
            new JProperty("Name", "Jeffrey"),
            new JProperty("Birthday", new DateTime(1990, 1, 1)),
            new JProperty("Level", 99),
            new JProperty("Records",
                new JArray(
                    new JValue(1024), new JValue(9999),
                    new JValue(32767)
                    )
                )
            );
        string jsonString = JsonConvert.SerializeObject(jo);
        Response.Write(jsonString);
        Response.Write("<hr />");
 
/* 
 jsonString內容為
{"Name":"Jeffrey","Birthday":"\/Date(631123200000+0800)\/","Level":99,
 "Records":[1024,9999,32767]} 
 */
 
        //JSON字串也可還原回JObject,動態存取
        JObject restoredObject = JsonConvert.DeserializeObject<JObject>(
            jsonString);
        //JObject可使用LINQ方式存取
        var q = from p in restoredObject.Properties()
                where p.Name == "Name"
                select p;
        Response.Write("<li>Name = " + (string)q.First().Value);
        Response.Write("<li>Birthday = " +
            (DateTime)jo.Property("Birthday").Value);
        int[] records =
            ((JArray)jo.Property("Records").Value)
            .Select(o => (int)o).ToArray();
        Response.Write("<li>Records = " + string.Join(",", 
            records.Select(o => o.ToString()).ToArray()));
 
        /*
         * == 得到結果 ==
         * Name = Jeffrey
         * Birthday = 1/1/1990 12:00:00 AM
         * Records = 1024,9999,32767
         */
 
        Response.End();
    }
}

Comments

# by 阿誠

幫助很多,感謝!

Post a comment