处理JSON数据

《Silverlight 2 & ASP.NET高级编程》第9章创建用户界面,本章将介绍如何使用Silverlight的网络和通信功能来访问分布式数据。本章将涵盖如何创建Silverlight可以调用的服务,讨论处理跨域问题的不同方法,并介绍Silverlight内置的、用于处理数据的类。本节为大家介绍处理JSON数据。

AD:

9.5.3  处理JSON数据

Silverlight为解析从Web服务、REST API或者其他类型所返回的XML数据提供了非常优秀的支持。由于许多服务均返回XML数据,因此在Silverlight应用程序中,诸如XmlReader、XmlSerializer或XDocument之类的类会频繁被使用。但是,XML数据并不是可以从服务返回的唯一数据类型。服务也可能支持JavaScript对象表示(Java Script Object Notation,JSON)。该格式为客户端和服务之间交换数据提供了一种压缩的方法。JSON最初设计是和JavaScript语言一起使用,但是很多情况下,需要在Silverlight中利用诸如C#或者VB.NET之类的语言对它进行处理。在这些情况下,可以使用Silverlight的DataContractJsonSerializer类,该类支持将CLR对象序列化为JSON以及将JSON消息反序列化为CLR对象。

DataContractJsonSerializer类位于System.Runtime.Serialization.Json名称空间中。为了使用该类,需要在Silverlight项目中引用System.ServiceModel.Web程序集。DataContractJson Serializer的结构和功能均和前面所讨论的XmlSerializer类非常类似。它提供了诸如ReadObject的方法以实施反序列化,而提供了WriteObject方法以实施序列化。ReadObject方法接受一个包含需要反序列化的JSON数据的流作为参数,而WriteObject方法则以源对象以及序列化后的JSON数据流作为参数。两个方法的签名如下所示:

  1. public Object ReadObject(  
  2. Stream stream  
  3. )  
  4.  
  5. public void WriteObject(  
  6. Stream stream,  
  7. Object graph  

1. JSON基础

包括由Flickr所提供的服务的很多REST API,均允许数据以JSON格式返回。JSON利用括弧来区分不同的对象,并利用冒号将属性名和属性值实施分离。下面的例子利用JSON将来源于Flickr的图像数据传递给某个客户端:

  1. {  
  2. "id":"555242564", "owner":"555371@N00", "secret":"555afd69d",  
  3. "server":"2226", "farm":3, "title":"Camp Chihuahua: Class In Session",  
  4. "ispublic":1, "isfriend":0, "isfamily":0  

该JSON片段利用{和}字符指定了照片数据在哪开始到哪结束,利用冒号将属性名和属性值分离,并利用逗号分隔不同的属性。如下所示,利用方括号可以定义一个photo对象的数组:

  1. {  
  2. "photo":  
  3. [  
  4. {  
  5. "id":"2386242564", "owner":"3911171@N00", "secret":"555afd69d",  
  6. "server":"2226","farm":3,"title":"Camp Chihuahua: Class In Session",  
  7. "ispublic":1, "isfriend":0, "isfamily":0  
  8. },  
  9. {  
  10. "id":"2386239664", "owner":"25111971@N02", "secret":"555cced92",  
  11. "server":"3229", "farm":4, "title":"kid and dog",  
  12. "ispublic":1, "isfriend":0, "isfamily":0  
  13. }  
  14. ]  

如下面的JSON消息所示,通过添加嵌套的括号,对象也可以定义子对象:

  1. {  
  2. "photos":  
  3. {  
  4. "page":1, "pages":32047, "perpage":100, "total":"3204603",  
  5. "photo":  
  6. {  
  7. [  
  8. {  
  9. "id":"2386242564", "owner":"3911171@N00", "secret":"555afd69d",  
  10. "server":"2226", "farm":3, "title":"Camp Chihuahua: Class In Session",  
  11. "ispublic":1, "isfriend":0, "isfamily":0  
  12. },  
  13.  
  14. {  
  15.  
  16. "id":"2386239664", "owner":"25111971@N02", "secret":"555cced92",  
  17. "server":"3229", "farm":4, "title":"kid and dog", "ispublic":1,  
  18. "isfriend":0, "isfamily":0  
  19. }  
  20. ]  
  21. }  
  22. },  
  23. "stat":"ok"}  

2. 使用DataContractJsonSerializer类

为了使用DataContractJsonSerializer类,并不需要完整地理解JSON消息格式,因为它处理了数据的序列化和反序列化过程。但是,需要足够了解相关知识,以在Silverlight应用程序中创建JSON数据可以被反序列化成的匹配CLR类。映射为前面所示的JSON消息例子的类如下所示:

  1. public class FlickrResponse  
  2. {  
  3. public string stat { get; set; }  
  4. public photos photos { get; set; }  
  5. }  
  6.  
  7. public class photos  
  8. {  
  9. public int page { get; set; }  
  10. public int pages { get; set; }  
  11. public int perpage { get; set; }  
  12. public int total { get; set; }  
  13. public photo[] photo { get; set; }  
  14. }  
  15.  
  16. public class photo  
  17. {  
  18. public string id { get; set; }  
  19. public string owner { get; set; }  
  20. public string secret { get; set; }  
  21. public string title { get; set; }  
  22. public int ispublic { get; set; }  
  23. public int isfriend { get; set; }  
  24. public int isfamily { get; set; }  
  25. public string server { get; set; }  
  26. public string farm { get; set; }  
  27. //Custome properties used for data binding  
  28. public string Url { get; set; }  
  29. public ImageBrush ImageBrush { get; set; }  

注意,在每个类中定义的属性均和包含在该JSON消息中的属性大小写匹配。这种大小写的匹配甚至应用到了子类的名称上,如photos和photo。这正是JSON消息正确反序列化的精华所在!JSON消息和CLR对象之间大小写的不匹配将导致数据丢失。

为了反序列化JSON消息,可以调用DataContractJsonSerializer类的ReadObject方法,并为该方法传递一个包含JSON数据的流作为参数。下面所示的例子检索了来自Flickr REST服务的数据,并将其进行了反序列化。数据是利用HttpWebRequest和HttpWebResponse对象进行检索的。而反序列化JSON数据的代码则位于GetJSONResponse CallBack方法中。注意,JSON数据将被反序列化到CLR对象的类型,传递给了DataContractJsonSerializer类的构造函数。

  1. private Uri CreateJSONUri()  
  2. {  
  3. return new Uri(String.Format("{0}?method={1}&api_key={2}&text={3}" +  
  4. "&per_page={4}&format=json&nojsoncallback=1",  
  5. _BaseUri, "flickr.photos.search", _APIKey, this.txtSearchText.Text,   
  6. 50));  
  7. }  
  8.  
  9. private void StartJsonRequest()  
  10. {  
  11. //Add reference to System.Net.dll if it's not already referenced  
  12. HttpWebRequest request = (HttpWebRequest)WebRequest.Create  
  13. (CreateJSONUri());  
  14. //Start async REST request  
  15. request.BeginGetResponse(new AsyncCallback(GetJSONResponseCallBack),   
  16. request);  
  17. }  
  18.  
  19. private void GetJSONResponseCallBack(IAsyncResult asyncResult)  
  20. {  
  21. JSON.FlickrResponse res = null;  
  22. HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;  
  23. using (HttpWebResponse response =  
  24. (HttpWebResponse)request.EndGetResponse(asyncResult))  
  25. {  
  26. Stream dataStream = response.GetResponseStream();  
  27. //Deserialize JSON message into custom objects  
  28. DataContractJsonSerializer jsonSerializer =  
  29. new DataContractJsonSerializer(typeof(JSON.FlickrResponse));  
  30. jsonObj = (JSON.FlickrResponse)jsonSerializer.ReadObject  
  31. (dataStream);  
  32. Dispatcher.BeginInvoke(() => ProcessJsonObject(jsonObj));  
  33. }  
  34. }  
  35.  
  36. private void ProcessJsonObject(JSON.FlickrResponse jsonObj)  
  37. {  
  38. //Assign Url to each photo object as well as ImageBrush to paint photo  
  39. if (jsonObj != null && jsonObj.photos.photo != null)  
  40. {  
  41. foreach (JSON.photo photo in jsonObj.photos.photo)  
  42. {  
  43. photo.Url = this.CreateJSONPhotoUrl(photo);  
  44. ImageBrush brush = new ImageBrush();  
  45. brush.ImageSource = new BitmapImage(new Uri(photo.Url));  
  46. brush.Stretch = Stretch.Uniform;  
  47. photo.ImageBrush = brush;  
  48. }  
  49. DisplayJSONPhotos(jsonObj.photos.photo);  
  50. }  
  51. else  
  52. {  
  53. ShowAlert("Unable to proces photo data.");  
  54. }  
  55. }  
  56.  
  57. private string CreateJSONPhotoUrl(JSON.photo photo)  
  58. {  
  59. //http://farm{farm-id}.static.flickr.com/{server-id}/{id}_{secret}_  
  60. {size}.jpg  
  61. //farm-id: 1  
  62. //server-id: 2  
  63. //photo-id: 1418878  
  64. //secret: 1e92283336  
  65. //size: m, s, t, b  
  66.  
  67. return String.Format(_BasePhotoUrl, photo.farm, photo.server,   
  68. photo.id,photo.secret, "s");  
  69. }  
  70.  
  71. private void DisplayJSONPhotos(JSON.photo[] photos)  
  72. {  
  73. if (photos != null && photos.Length > 0)  
  74. {  
  75. this.icPhotos.ItemsSource = photos;  
  76. }  
  77. else  
  78. {  
  79. ShowAlert("No photos found.");  
  80. }  
posted @ 2011-07-12 12:02  俗雅冰山  阅读(574)  评论(0编辑  收藏  举报