2011年3月18日 星期五

在WP7/Silverlight當中接收JSON資料...

事情是這樣的,可能很多開發人員已經清楚,在Silverlight技術當中是不直接支援以ADO.NET方式來存取遠端DB的,關於這個部分,我在許多課堂中都有說明,隨著技術的改變與更新,現在有更好的方式在SL當中抓取資料,我們主要使用的是LINQ技術,在伺服器端可以配合LinqToSql和ADO.NET Entity Framework,所以我們會建議開發人員,在撰寫SL要呼叫的Web/WCF Services時,就直接透過LinqToSql or ADO.NET EF抓取資料,並且把抓到的資料直接以物件的方式回傳,這樣有一個超級棒的好處,就是在Silverlight去reference這個Web/WCF Services時,VS2010會自動在Silvelright端幫你generate這個物件的Type,然後你可以輕鬆的在SL當中使用這個物件,如同這個物件從伺服器端被傳到用戶端一樣。

例如:
[WebMethod]
        public AddrssBook[] getAllData()
        {
            AddrBookDataContext db = new AddrBookDataContext();
            var ret = from c in db.AddrssBooks select c;

            return ret.ToArray();
        }
這邊的AddressBook類別是資料表名稱,是LinqToSql自動幫我們產生的類別定義。

當SL去呼叫這個Web Services時,在Silvelright端就會自動產生該類別(從Win/Web Form時代就是這樣),一切都相當容易。

但在這個多元化的時候,很可能有時候沒那麼單純,總是有很多奇怪的場合,你的客戶會要求你達成跨平台這個遠大的目標。這時候,你要考慮Services是不是有可能要讓其他開發技術(PHP? Java? @#$%^&*@#$%?)來呼叫...因此,把資料轉成大家看得懂並且容易解析的方式會比較理想,例如JSON...

JSON是啥我就不多說了,有興趣的看這邊

所以呢,程式分成兩段,要如何在伺服器端把回傳的資料型別改成JSON呢? 很簡單,JSON只是字串,所以只需要把由LinqToSql抓到的資料經過轉換,程式如下:
//從LinqToSql抓資料            
AddrBookDataContext db = new AddrBookDataContext();
var ret = from c in db.AddrssBooks select c;
//轉JSON
string buf=ObjectToJson(ret.ToArray());
//把buf回傳...
...略...

//物件轉成JSON字串
private static string ObjectToJson(object obj, Type type)
{
    //Create a stream to serialize the object to.
    MemoryStream ms = new MemoryStream();

    // Serializer the User object to the stream.
    DataContractJsonSerializer ser = new DataContractJsonSerializer(type);
    ser.WriteObject(ms, obj);
    byte[] json = ms.ToArray();
    ms.Close();
    return Encoding.UTF8.GetString(json, 0, json.Length);
}
接著丟給Services網用戶端(Silverlight)傳,當用戶端接收到這個字串時,再透過底下程式碼轉回物件:
AddressBook[] addrs=JsonToObj(接收到的JsonString, typeof(AddressBook));
//將JSON轉回物件
private static object JsonToObj(string json, Type type)
{
    object obj;
    MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(json));
    DataContractJsonSerializer ser = new DataContractJsonSerializer(type);
    obj = ser.ReadObject(ms);
    ms.Close();
    return obj;
}
當然,由於沒有VS2010貼心的幫你在add services reference後自動產生那個AddressBook類別,因此你得自己在用戶端建立一個一樣的類別,為了省事,我多半偷偷copy Services裡LinqToSql幫我generate出來的code...

如此一來,你的用戶端(SL)既可以順利讀取到伺服器端的資料,其他開發技術所撰寫出來的程式也可以共享伺服器端的服務所傳遞的資料了。

這樣的模式非常常見,例如FaceBook, DropBox等知名網站的API,都可傳遞Json類型的資料,以便於用戶端讀取和使用。

而對於.NET來說,最主要的就是DataContractJsonSerializer這個類別,相關的資料可以在MSDN找到。

分享

沒有留言: