I have been working/collaborating on a project the past while that will be a mobile application and a location based service.

At the back-end it is being designed and developed from the ground up to be scalable and high performance. It has to be cause we want this thing rolled out on the millions of mobile phones out there be they iPhone, Android or Windows Phone 7.

At the back-end all data, with the exception of some reference data that is retrieved from SQL Azure and loaded in to a memory cache, is retrieved from and persisted to Azure Table Storage.

To expose some data and make it portable to all the devices I am making use of WCF Data Services which enables simple queries against the data store for things like lookup data (think genders, countries, anything that is relatively static) and expose them as an ATOM feed.

For everything else I am using good old Json serialization of objects.

Now I don’t know how iPhone and Android handle the de-serialization on their side, I am leaving that to the devs that are coding up the apps for those phones, but I did need to know how to do this for the Windows Phone 7 platform which I am working on at the moment.

Read on for how I handled it.

Part 1 – The WCF Data Service and Azure side of the equation

Ok so on the Server side I have a series of TableServiceEntities that are just classes that know how to persist and retrieve themselves from Azure Table Storage. I won’t go in to detail on the Azure side of things as it’s not what this article is all about.

The classes the application has are things like:

  • User
  • UserDevice
  • Activity
  • GeoCodeResult
  • Route

When making a call to service methods the application can return 1 or more of these objects and in addition it can return either a single object or a collection of the objects.

So to keep things simple every one of the WCF Data Service calls return a string which is in fact a Json encoded object of type JsonResponseMessage.

(Yes I know. I could have used something other other than WCF Data Services for doing this BUT it lets me blend different techniques from the one API, hence the choice of WCF Data Services).

That JsonResponseMessage is a custom class that the application implements and currently it looks like this:

publicclass JsonResponseMessage { publicbool Success { get; set; } publicstring Message { get; set; } publicint TotalPages { get; set; } publicint SelectedPage { get; set; } public User User { get; set; } public UserDevice UserDevice { get; set; } public Activity Activity { get; set; } public List GeoCodes { get; set; } privatevoid Clean(List entities) { foreach (ISensitive item in entities) { ((ISensitive)item).Clean(); } } publicstring Serialize() { List items = new List(); if (this.User != null){items.Add(this.User);} if (this.UserDevice != null) { items.Add(this.UserDevice); } if (this.Activity != null) { items.Add(this.Activity); } Clean(items); var jsonSerializer = new System.Web.Script.Serialization.JavaScriptSerializer(); return jsonSerializer.Serialize(this); } }

So as an example I have a method of the following signature:

publicstring FindPostCodesFromGeo( double latitude , double longitude , double minDistance , double maxDistance , int pageSize , int pageSelected)

It accepts a series of parameters and returns a string. That string is the Json encoded JsonResponseMessage and in this case will contain the following:

JsonResponseMessage response = new JsonResponseMessage(); response.Success = true; response.Message = string.Format("Search found {0} item(s)", total); response.TotalPages = Helpers.CalculatePageCount(total, pageSize); ; response.SelectedPage = pageSelected; response.GeoCodes = pagedResults; return response.Serialize();

Where pagedResults is of type List and this is was the result looks like:

<FindPostCodesFromPostCode>{"Success":true,"Message":"Search found 35 item(s)",

"TotalPages":7,"SelectedPage":1,"User":null,"UserDevice":null,"Activity":null,

"GeoCodes":[{"PartitionKey":"Australia","RowKey":"NSW-BONDI JUNCTION-1355-PO Boxes","Key":"1355","Type":"PostCode","Description":"BONDI JUNCTION - PO Boxes","Latitude":-33.893739,"Longitude":151.262502,"DistanceFromTarget":0},

{"PartitionKey":"Australia","RowKey":"NSW-BONDI-2026-","Key":"2026","Type":"PostCode","Description":"BONDI","Latitude":-33.893739,"Longitude":151.262502,"DistanceFromTarget":0},

{"PartitionKey":"Australia","RowKey":"NSW-BONDI BEACH-2026-","Key":"2026","Type":"PostCode","Description":"BONDI BEACH","Latitude":-33.893739,"Longitude":151.262502,"DistanceFromTarget":0},

{"PartitionKey":"Australia","RowKey":"NSW-NORTH BONDI-2026-","Key":"2026","Type":"PostCode","Description":"NORTH BONDI","Latitude":-33.893739,"Longitude":151.262502,"DistanceFromTarget":0},

{"PartitionKey":"Australia","RowKey":"NSW-TAMARAMA-2026-","Key":"2026","Type":"PostCode","Description":"TAMARAMA","Latitude":-33.893739,"Longitude":151.262502,"DistanceFromTarget":0}]}

FindPostCodesFromPostCode>

Mmmm look at all that Json goodness and notice that items that are not returned by this call are just set to null.

Part 2 – The Windows Phone 7 side of the equation

Right, so we have our service exposed and we are returning lots of lovely Json data. But how do we consume that in an object based way without having to doing any nasty parsing on the Json data?

Ok here we go. First off we are not (in this instance) making any reference to the WCF Data Service from our Windows Phone 7 app. We could (and in fact I do for other static data) but for the purposes of this example no service reference is required.

I start off by composing my request string:

string request = string.Format("{0}/FindPostCodesFromGeo?latitude={1}&longitude={2}

&minDistance={3}&maxDistance={4}&pageSize={5}&pageSelected={6}", Settings.MyServer, watcher.Position.Location.Latitude, watcher.Position.Location.Longitude,

0, 10, 20, pageSelected);

This is just a standard Get request to a URL composed of parameters I have collected, such as Latitude and Longitude from the GeoCoordinateWatcher class provided by Windows Phone 7, distance to search and paging information.

The next step is to create a WebClient and make an ASynch call to the service:

//// Create a web client and send the request WebClient doSearch = new WebClient(); doSearch.OpenReadAsync(new Uri(request)); doSearch.OpenReadCompleted += new OpenReadCompletedEventHandler(doSearch_OpenReadCompleted);

The final step in the process is to handle the result of out request and that is shown below. Note that we have to know about the type of object we are expecting to return from the request and I will come to that in a moment.

XDocument doc = XDocument.Load(e.Result); byte[] byteArray = Encoding.UTF8.GetBytes(doc.Document.Root.Value); using (MemoryStream ms = new MemoryStream(byteArray)) { DataContractJsonSerializer s = new DataContractJsonSerializer(typeof(JsonResponseMessage), new[] { typeof(GeoCodeResult) }); JsonResponseMessage data = (JsonResponseMessage)s.ReadObject(ms); if (data.Success) { foreach (GeoCodeResult item in data.GeoCodes) { Pushpin pin = new Pushpin() { Location = new GeoCoordinate(item.Latitude,item.Longitude) }; LocalMap.Children.Add(pin); } } else { MessageBox.Show(string.Format("We had a problem with the search: {0}", data.Message)); } }

So what’s going on here? Well the result from the request is returned in the e.Result and this is the Json encoded string that we saw earlier in the article.

We load that in to an XDocument (found in the System.Xml.Linq namespace) and we get the body of the response like so; doc.Document.Root.Value and turn that in to a byte[] to load in to a MemoryStream.

Now here comes the magic. We create a DataContractJsonSerializer, which is found in the System.Runtime.Serialization.Json namespace and we need to tell it the type of object we are de-serializing (the 1st parameter) along with any additional types that may be contained in the object graph (the 2nd parameter).

So that 2nd parameter will contain an array of the types of object that this specific call will be returning. In this case it is just the GeoCodeResult object that is being returned or a list of them in this case.

The final step is to call the ReadObject method of our DataContractJsonSerializer instance and pass in the MemoryStream which is our object graph.

Once we have that done then we have our JsonResponseMessage re-hydrated from the server and we can work with it in an object based way from the comfort of our C# code. No string parsing necessary.

Final thoughts

Now I mentioned I would come back to needing to know about the type of objects we are returning.

If the objects I was returning didn’t inherit from TableServiceEntity then I could have a shared library of my models and just reference this in my Windows Phone 7 project. I could also (and may still yet) create additional lightweight classes that don’t inherit from TableServiceEntity and pop those in a library. Of course that means once I have retrieved the data on the server I have to convert it first before passing it back.

However, in the interest of speed in this development I have just re-implemented the classes with the same structure in my Windows Phone 7 app and that works fine.

As I write this I can already see some heavy refactoring coming on the horizon and that’s fine now that I have an implementation in place.

I hope this article helps someone out there as I spent some time and many hours of googling looking for a solution to de-serializing Json in to objects in Windows Phone 7.

BondiGeek