Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

Windows 8 applications and JSON data

For anyone that wants to call various JSON data service endpoints in a Windows 8 (Metro style?) application, there’s a couple of changes in “.NET APIs for Metro style apps” (using MSDN terminology here) that needs to be looked into. For this blog post I’m using flickr API as an example of how to fetch and parse JSON data.

Where’s my WebClient?

No, there is no WebClient class in the new API. But…

There’s a HttpClient class that works similar, or even better, by providing an asynchronous method to fetch data. If you’ve looked into the Async CTP bits, the new method should look very familiar.

The new HttpClient class itself resides into the System.Net.Http namespace. Jumping right into the code:

public async Task<string> GetPhotosStream()
{
    HttpClient client = new HttpClient();
    string url = "http://www.flickr.com/services/rest/?method=flickr.photos.search&format=json&nojsoncallback=1&api_key=<yourkey>&text=buildwindows";
    HttpResponseMessage response = await client.GetAsync(url);
    return response.Content.ReadAsString();
}

Shall anyone need it, there is also a synchronous method called Get() that will block until full response message is returned and read on the client.

Other than Get(Async), there are three method pairs more – Get(Async), together with Put(Async), Post(Async) and Delete(Async) forms the full set of verbs supported by REST (Representational state transfer) to manipulate data.

GetAsync() will return a HttpResponseMessage, which contains the returned status code, response headers and returned content, which can be read in a variety of ways.

Parsing JSON

I have rarely used native framework JSON classes (I prefer using JSON.Net), but looking at the new API it looks like there’s quite a few changes here as well.

A returned string can be fed to the JsonObject in its constructor or using Parse() method on its instance. Either way will result in an exception if the JSON string is invalid and couldn’t be parsed.

Once parsed, you’ve got full access to it’s structure. Before I show the code to access it, let’s look at snippet of the returned JSON string:

{
  "photos":
  {
    "page":1, 
    "pages":1, 
    "perpage":100, 
    "total":"13", 
    "photo":
    [
      {"id":"6146549133", ..., "title":"20 Microsoft interns (three from Olin) at this week's BUILD conference", ...},
      {"id":"6146244616", ..., "title":"Internet Explorer", ...},
      ...
      ...
    ]
  },
  "stat":"ok"
}

And this is how you would read the titles of returned photos:

private static List<string> titles = new List<string>();

public static async void ExaminePhotos()
{
    string responseText = await GetPhotosStream();
    JsonObject root = new JsonObject(responseText);
    bool isSuccess = root.GetNamedString("stat") == "ok";
    JsonObject info = root.GetNamedObject("photos");
    int page = (int)info.GetNamedNumber("page");
    int totalPages = (int)info.GetNamedNumber("pages");
    JsonArray photos = info.GetNamedArray("photo");
    for (uint i = 0; i < photos.Count; i++)
    {
        string title = photos.GetObjectAt(i).GetNamedString("title");
        titles.Add(title);
    }
}

While the “Named*" methods return typed values (GetNamedString() returns a string, GetNamedNumber() a double, etc.), it’s also possible to get the JSON value by string indexer and later call to its typed value, e.g. json[“stat”].GetString(), which gets useful if you want to check for its type first.

The second part deals with a JsonArray named photo, which gets enumerated and read in a similar manner.

Wait, isn’t this supposed to be simpler?

Of course, the DataContractJsonSerializer is still here. In fact, it appears to be the same class, just moved into a separate assembly.

To use it, create appropriate classes from the JSON structure (one of utilities that can help) and deserialize JSON string with the help of DataContractJsonSerializer:

string responseText = await GetPhotosStream();

DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(RootObject));
RootObject root;
using (MemoryStream stream = new MemoryStream(Encoding.Unicode.GetBytes(responseText)))
{
    root = serializer.ReadObject(stream) as RootObject;
}

The result is a full object tree that was deserialized from the flickr API JSON string.