2017年2月28日 星期二

[C#.net] 產生JSON字串的幾種方式整理

這邊就以Google API裡有段JSON字串當作練習怎麼產生:
image

以下整理幾種我見過的方式(個人推薦的放在最後^_^)
1. 字串拼接
最麻煩的方式,可讀性也差,若遇到Boolean型別的變數要記得轉小寫


protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)//Get Method
        {
            //準備資料
            string collapse_key = "score_update";
            int time_to_live = 108;
            bool delay_while_idle = true;
            string score = "4x8";
            string time = "15:16.2342";
            List<string> registration_ids = new List<string>() { "4","8","15","16","23","42"};


            //開始拼接字串
            StringBuilder sb = new StringBuilder();
            sb.AppendLine("{");
            sb.AppendLine("\"collapse_key\":\""+collapse_key+"\",");
            sb.AppendLine("\"time_to_live\":"+time_to_live+",");
            sb.AppendLine("\"delay_while_idle\":"+delay_while_idle.ToString().ToLower()+",");
            sb.AppendLine("\"data\":{");
            sb.AppendLine("\"score\":\""+score+"\",");
            sb.AppendLine("\"time\":\""+time+"\"");
            sb.AppendLine("},");
            sb.AppendLine("\"registration_ids\":[");
            foreach (string item in registration_ids)
            {
                sb.Append("\""+item+"\",");
            }
            sb = new StringBuilder(sb.ToString().TrimEnd(','));//移除最後一個「,」字元
            sb.AppendLine("]");
            sb.AppendLine("}");

            //輸出結果
            Response.Write(sb.ToString());
        }
    }
↑所以很多人會尋找第三方套件來處理吧
以下便介紹Json.net,因為威力太強大了~
image

有了Json.net後就可以使用Json.net的函數產生JSON字串
2. 使用JsonTextWriter
用法很像XmlTextWriter,寫起來有點囉嗦,平常工作我不會用這個

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)//Get Method
        {
            //準備資料
            string collapse_key = "score_update";
            int time_to_live = 108;
            bool delay_while_idle = true;
            string score = "4x8";
            string time = "15:16.2342";
            List<string> registration_ids = new List<string>() { "4","8","15","16","23","42"};

             
            //要輸出的變數
            StringWriter sw = new StringWriter();
            //建立JsonTextWriter
            JsonTextWriter writer = new JsonTextWriter(sw);
            writer.WriteStartObject();
            writer.WritePropertyName("collapse_key"); writer.WriteValue(collapse_key);
            writer.WritePropertyName("time_to_live"); writer.WriteValue(time_to_live);
            writer.WritePropertyName("delay_while_idle"); writer.WriteValue(delay_while_idle);
            writer.WritePropertyName("data");
            writer.WriteStartObject();
            writer.WritePropertyName("score"); writer.WriteValue(score);
            writer.WritePropertyName("time"); writer.WriteValue(time);
            writer.WriteEndObject();
            writer.WritePropertyName("registration_ids"); 
            writer.WriteStartArray();
            foreach (string item in registration_ids)
            {
                writer.WriteValue(item);
            }
            writer.WriteEndArray();
            writer.WriteEndObject();
 
            //輸出結果
            Response.Write(sw.ToString());
        }
    }
3. 使用JObject匿名物件
比起JsonTextWriter簡化了許多,不過大概是每個Property和值都要再寫一次建構子名稱,我覺得還是有點麻煩

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)//Get Method
        {
            //準備資料
            string collapse_key = "score_update";
            int time_to_live = 108;
            bool delay_while_idle = true;
            string score = "4x8";
            string time = "15:16.2342";
            List<string> registration_ids = new List<string>() { "4","8","15","16","23","42"};

            //JObject匿名物件
            JObject obj = new JObject(
                 new JProperty("collapse_key",collapse_key),
                 new JProperty("time_to_live",time_to_live),
                 new JProperty("delay_while_idle",delay_while_idle),
                 new JProperty("data",
                     new JObject(
                         new JProperty("score",score),
                         new JProperty("time",time))),
                new JProperty("registration_ids",registration_ids)
                );
 
            //序列化為JSON字串並輸出結果
            Response.Write(JsonConvert.SerializeObject(obj,Formatting.Indented));
        }
    }

那有沒有寫起來直覺,程式碼又短少的方式呢?
請看以下兩個
4. 物件序列化
這個要先知道輸出的json字串長什麼樣子
貼到http://json2csharp.com/去產生類別程式碼
image
然後


    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)//Get Method
        {
            //準備資料
            string collapse_key = "score_update";
            int time_to_live = 108;
            bool delay_while_idle = true;
            string score = "4x8";
            string time = "15:16.2342";
            List<string> registration_ids = new List<string>() { "4","8","15","16","23","42"};

             
            //建立物件,塞資料
            RootObject root = new RootObject();
            root.collapse_key = collapse_key;
            root.time_to_live = time_to_live;
            root.delay_while_idle = delay_while_idle;
            Data data = new Data();
            root.data = data;
            root.data.score = score;
            root.data.time = time;
            root.registration_ids = registration_ids;
            //物件序列化
            string strJson = JsonConvert.SerializeObject(root, Formatting.Indented); 
            //輸出結果
            Response.Write(strJson);
        }
    }
或使用物件初始化方式塞值

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)//Get Method
        {
            //準備資料
            string collapse_key = "score_update";
            int time_to_live = 108;
            bool delay_while_idle = true;
            string score = "4x8";
            string time = "15:16.2342";
            List<string> registration_ids = new List<string>() { "4","8","15","16","23","42"};

             
            //建立物件,塞資料
            RootObject root = new RootObject()
            {
                collapse_key = collapse_key,
                time_to_live = time_to_live,
                delay_while_idle = delay_while_idle,
                data = new Data() 
                { 
                   score = score,
                   time=time
                },
                registration_ids = registration_ids
            };
            
            //物件序列化
            string strJson = JsonConvert.SerializeObject(root, Formatting.Indented); 
            //輸出結果
            Response.Write(strJson);
        }
    }
使用物件初始化方式塞值看起來直覺多了
不過為了物件序列化還要特地宣告類別,這…倒不如使用Linq吧

5.用Linq+匿名物件寫法 直接組JSON
這招在Json.net的官方文件有範例(用JObject.FromObject的那個):http://james.newtonking.com/projects/json/help/html/CreatingLINQtoJSON.htm
但只有範例,沒寫為什麼Linq要那樣寫,誰看得懂阿XD
要用Linq直接組JSON
大概把握幾點:
Json Object:Json字串用大括號{}表示,Linq也是用大括號{}表示
Json Object的Name(Key、Property):Json字串在兩個雙引號””裡寫一個英文單字,Linq就直接寫英文單字即可
Json Array:Json字串用中括號[]表示,Linq就用from o in XXX select o,這種回傳IEnumerable的寫法(如果JSON字串是物件陣列的話就用from o in XXX select new {欄位1=YYY}這種形式)
Json Value:Linq就看Json字串填什麼值就跟著填什麼值

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)//Get Method
        {
            //準備資料
            List<string> registration_ids = new List<string>() { "4", "8", "15", "16", "23", "42" };

            //用Linq直接組
            var result = new
                            {
                                collapse_key = "score_update",
                                time_to_live = 108,
                                delay_while_idle = true,
                                data = new{
                                    score ="4x8",
                                    time = "15:16.2342"
                                },
                                registration_ids = from s in registration_ids
                                                            select s

                            };

            //序列化為JSON字串並輸出結果
            Response.Write(JsonConvert.SerializeObject(result));
        }
    }
請看圖示解說↓
image
由於Linq支援DataTable的查詢,所以再難的JSON格式都組得出來,不用再跑for迴圈寫一堆Code,開發速度大幅提昇
以下截自實務上的一段Code(有做了一點修改)

                DataTable dt = new DataTable();//撈出一張資料表的所有數據(這個表類似北風資料庫的員工資料表,有階層關係)
                DataTable dtDetail = new DataTable();//上一張表的一對多明細表
                var firstLevel = dt.Select("pid is NULL");//第一層數據
                var result = new
                {
                      Info = new
                    {
                        Level1 = from a in firstLevel
                                 join b in dt.AsEnumerable() on a.Field<int>("id") equals b.Field<int?>("pid") into secondLevel
                                 select new
                                 { 
                                     Title =  a.Field<string>("Title"),
                                     Level2 = secondLevel.Select(c => new
                                     {
                                         Title =  c.Field<string>("Title"),
                                         Photos = from s in secondLevel 
                                                       join uu in dtDetail.AsEnumerable() on s.Field<int>("id") equals uu.Field<int>("id")
                                                       where s.Field<int>("id") == c.Field<int>("id")
                                                select new
                                                {
                                                    PhotoID = uu.Field<string>("PhotoID"),
                                                    PhotoTitle = uu.Field<string>("PhotoTitle")
                                                }

                                     })
                                 }
                    }
                };
※不過要注意對於寫的人是寫很快,後人維護會有閱讀困難的可能
最後附上一張比較圖
image

2012.11.09 追記
最後一個方法,直接使用Linq產生Json字串有個缺點要提一下
Linq匿名型別的屬性無法給null值,如下圖

image

from : https://dotblogs.com.tw/shadow/archive/2012/08/16/74099.aspx

Json.Net 用法

首先用最基本的JsonTextWriter和JsonTextReader
JsonTextWriter使用成對的方法來輸出Json字串
JsonTextReader使用Read方法來持續讀取Json字串
看得出來在使用上有點拖泥帶水
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
static void Main(string[] args)
{
    string jsonString = string.Empty;
 
    using (StringWriter sw = new StringWriter())
    {
        using (JsonTextWriter writer = new JsonTextWriter(sw))
        {
            // 開始輸出物件
            writer.WriteStartObject();
 
            // 輸出屬性:id
            writer.WritePropertyName("id");
            writer.WriteValue(1);
 
            // 輸出屬性:name
            writer.WritePropertyName("name");
            writer.WriteValue("xian");
 
            // 輸出屬性today
            writer.WritePropertyName("today");
            writer.WriteValue(DateTime.Today);
 
            // 開始輸出陣列
            writer.WritePropertyName("arraydata");
            writer.WriteStartArray();
            writer.WriteValue(1);
            writer.WriteValue(2);
            writer.WriteValue(3);
 
            // 結束輸出陣列
            writer.WriteEndArray();
 
            // 結束串出物件
            writer.WriteEndObject();
        }
 
        jsonString = sw.ToString();
        Console.WriteLine(jsonString);
    }
 
    using (StringReader sr = new StringReader(jsonString))
    {
        using (JsonTextReader reader = new JsonTextReader(sr))
        {
            while (reader.Read())
            {
                if (reader.Value != null)
                {
                    Console.WriteLine("token:{0}, value:{1}", reader.TokenType, reader.Value);
                }
                else
                {
                    Console.WriteLine("token:{0}", reader.TokenType);
                }
            }
        }
    }
 
    Console.ReadLine();
}

執行結果

使用JObject可以簡化一點
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 淮備Json資料
JObject obj1 = new JObject()
{
    new JProperty("id", 1),
    new JProperty("name", "xian"),
    new JProperty("today", DateTime.Today),
    new JProperty("arraydata",
    new JArray()
    {
        new JValue(1),
        new JValue(2),
        new JValue(3),
    })
};
 
string jsonString = obj1.ToString();
Console.WriteLine(jsonString);
 
// 解析Json格式
JObject obj2 = JObject.Parse(jsonString);
Console.WriteLine(
    "id:{0}, name:{1}, today:{2}, arraydata:{3}",
    obj2["id"],
    obj2["name"],
    obj2["today"],
    obj2["arraydata"]);
Console.ReadLine();
執行結果

最常使用還是JsonConvert這一個方式,用法也很直覺

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 淮備資料
Person p1 = new Person()
{
    id = 1,
    name = "xian",
    today = DateTime.Today
};
 
// 序列化物件
string jsonString = JsonConvert.SerializeObject(p1);
Console.WriteLine("jsonstring:{0}", jsonString);
 
// 反序列化物件
Person p2 = JsonConvert.DeserializeObject<Person>(jsonString);
Console.WriteLine("id:{0}, name:{1}, today:{2}", p2.id, p2.name, p2.today);
 
Console.ReadLine();
執行結果

from : http://blog.developer.idv.tw/2013/06/jsonnet.html