針對 Web API 回轉的Json to Class

Web API

JSON轉型

之前都是寫Web API 讓人使用

角色總有輪替的一天,也換到我得去call 別人寫好的 Web API 

然而我們會遇到一個問題,就是Web API 通常來說都會回轉成Json的格式

那我們怎麼將Json的格式轉成我們要的類別呢?

或是有沒有其他更方便的做法

通常而言,我們利用 HttpWebRequest 可以直接呼叫到對方提供的Web API,並把結果存下來

                HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("http://www.ExternalWebAPI");
                req.Method = "GET";
                req.ContentType = "application/json; charset=utf-8";
                req.Proxy.Credentials = System.Net.CredentialCache.DefaultNetworkCredentials;
                
                string strApiResult = "";
                using (WebResponse wr = req.GetResponse())
                {

                    using (var reader = new StreamReader(wr.GetResponseStream()))
                    {
                        strApiResult = reader.ReadToEnd();
                    }

                }

但Json回傳的結果,對C#來講是一個 anonymous class

但重點是,我們怎麼將這個anonymous class轉換成C#的強型別 class 呢?

一般來說會有兩種做法

1. 可不可以讓系統自己轉?

這是比較偷懶的做法,相信大多人也會想這樣做,程式碼也會少很多

沒錯,這絕對可行,且C# library 早就幫您準備好了,我們可以使用JavaScriptSerializer

但在做自動轉換時,你必須要知道Web API 會回傳出什麼樣的資料,而你也必須建立出一樣的資料結構才行

對於Json資料格式來說,一開始接觸的人可能會覺得它並沒有XML那麼易讀,既然有了XML為什麼要有Json呢?

我個人的見解是,XML固然好懂,若以同樣的一份資料來說,當資料量大的時候,XML的資料量就會遠遠超過Json了

在這個以Mobile裝置維生的環境,Json這樣的資料格式比起其他資料格式自然是占了上風

<order>012345</order>
{"order":"012345"}

Json格式既然比XML難看的懂,那到底有沒有什麼辦法呢?

有的,網路上早已有人寫好 Json parser的工具了,直接把Json文字貼進去,就有視覺化的資料結構可以一覽無遺了

使用方式應當很簡單 http://json.parser.online.fr/

既然有了視覺化效果的頁面,那能不能幫把我資料生成我要的類別呢?

這也沒有問題,網路上的工具不怕沒有,就怕你不找

使用方法一樣容易,把Json丟進去就會幫你產生出相對應的Class,你所需要做的就是copy & paste

http://json2csharp.com/

重點戲來了,這樣真的可以轉成我們要的型別嗎?

是的,當然可以,不然我就不會寫這篇文章了

但是前提是你的class的properties的名字要對,且型別都要對的上,否則在做轉換的同時是會轉不過去的

當你的class propertes > Json properties 時, 也可以轉的過去,class properties 多的部份只會是null 

當你的Json properties > class propertes 時, 也可以轉的過去,class properties 少的部份本來就沒有

結論就是他只會針對properties的名字對的方去自動mapping

此時我們加上這兩行就大功告成啦!!! 灑花

ParkResultResponse 即是針對呼叫外部API 回轉回來的自定義class

                    using (var reader = new StreamReader(wr.GetResponseStream()))
                    {                        
                        strApiResult = reader.ReadToEnd();
                        JavaScriptSerializer js = new JavaScriptSerializer();
                        ParkResultResponse r = (ParkResultResponse)js.Deserialize(strApiResult, typeof(ParkResultResponse));
                        Console.WriteLine(r.result.count);
                    }

2. 手動轉

第一個方法已經很棒了啊,為什麼我們需要第二個方法?

有以下幾個原因

(1) 當資料過多時,我只需要部份資料,我不需要全轉出來

(2) 當對方的API 回轉的資料你沒有使用,且型別有變動時,你的程式不會死掉

(3) 對方API 定義的名字很鳥,你想對應到更有識別性的名字

(4) 自我挑戰

以下就要介紹這個作法 Dynamic

                    using (var reader = new StreamReader(wr.GetResponseStream()))
                    {
                        
                        strApiResult = reader.ReadToEnd();
                        JavaScriptSerializer js = new JavaScriptSerializer();
                        dynamic myObject = js.DeserializeObject(strApiResult);
                        Console.WriteLine(myObject["result"]["count"]);
                        Console.WriteLine(myObject["result"]["results"].Length);
                        Console.WriteLine(myObject["result"]["results"][0]["area"]);
                    }

這個方法也是透過JavaScriptSerializer物件方法轉成C# dynamic 物件

且採用的是Dictionary的方式來取值的

但最大的缺點就是採用的是弱型別,你必須事先知道階層關係與資料型別