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
重點戲來了,這樣真的可以轉成我們要的型別嗎?
是的,當然可以,不然我就不會寫這篇文章了
但是前提是你的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的方式來取值的
但最大的缺點就是採用的是弱型別,你必須事先知道階層關係與資料型別