Portable class libraries and fetching JSON

After much delay, we finally have the Windows Phone 8 SDK to go along with the Windows 8 Store SDK, or whatever ridiculous name they’re giving it these days. (Seriously… that no one could come up with a suitable replacement for “metro” is disappointing in an otherwise exciting set of product launches.) One of the neat-o things is the potential for code reuse, particularly across Windows 8 and Windows Phone 8 apps.

This is accomplished in part with portable class libraries, which allow you to share code between different types of projects. With some other techniques and quasi-hacks, you can share some amount of code, and I saw it mentioned in one of the Build videos that they’re seeing as much as 70% code reuse. Not bad.

However, I’ve already hit a super annoying snag. It appears that the HttpClient class, with its idiot-proof async goodness, is not included in the Windows Phone 8 class libraries. Shock, gasp, horror, disappointment, etc. The delay in releasing it already caused dismay among developers, and I’m sure this won’t help.

So I started refactoring some code I already had for a Windows 8 Store app (ugh) to accommodate the use of HttpWebRequest instead. I haven’t tried it in a Windows Phone 8 project beyond compiling, but it appears to work.

I used this StackOverflow answer as a starting point since it’s been a long time since I used HttpWebRequest, and keep in mind that it has no exception handling. It needs refinement. The goal here is to new up the client, and call a method that returns some deserialized JSON objects from the Intertubes. Adding facilities for headers or cookies is probably a good next step. You need to use NuGet for a Json.NET reference. So here’s the start:

using System.Net;
using System.Threading.Tasks;
using Newtonsoft.Json;
using System.IO;

namespace MahProject
{
    public class ServiceClient<T> where T : class
    {
        public ServiceClient(string url)
        {
            _url = url;
        }

        private readonly string _url;

        public async Task<T> GetResult()
        {
            var response = await MakeAsyncRequest(_url);
            var result = JsonConvert.DeserializeObject<T>(response);
            return result;
        }

        public static Task<string> MakeAsyncRequest(string url)
        {
            var request = (HttpWebRequest)WebRequest.Create(url);
            request.ContentType = "application/json";
            Task<WebResponse> task = Task.Factory.FromAsync(
                request.BeginGetResponse,
                asyncResult => request.EndGetResponse(asyncResult),
                null);
            return task.ContinueWith(t => ReadStreamFromResponse(t.Result));
        }

        private static string ReadStreamFromResponse(WebResponse response)
        {
            using (var responseStream = response.GetResponseStream())
                using (var reader = new StreamReader(responseStream))
                {
                    var content = reader.ReadToEnd();
                    return content;
                }
        }
    }
}

Calling it in some kind of repository class may look like this, if you wanted to return an array of Park objects (Park model class omitted because it doesn’t matter):

public class ParkRepo
{
    public async Task<Park[]> GetAllParks()
    {
        var client = new ServiceClient<Park[]>(http://superfoo/endpoint);
        return await client.GetResult();
    }
}

And then from inside your WP8 or W8S app (see what I did there?), when you load state or do some kind of UI event handler (making sure the method uses the async keyword):

var parkRepo = new ParkRepo();
var results = await parkRepo.GetAllParks();
// bind results to some UI or observable collection or something

Hopefully this saves you a little time.

2 Comments

  • We were shocked too to find that WP8 does not contain the async API's. Until I saw your solution I was having a hard time figuring out how to "await" on BeginGetResponse which does async in the old-fashioned way.

    What's funny is even WP8-specific pages in MSDN seems to make use of non-existent Async call :
    http://msdn.microsoft.com/en-us/library/windowsphone/develop/jj206950%28v=vs.105%29.aspx
    "await webReq.GetResponseAsync();"
    perhaps they know something we don't...

  • @Anthony, The Microsoft.Bcl.Async package actually contains extension methods for the Windows Phone 8 networking APIs: http://nuget.org/packages/Microsoft.Bcl.Async. Simply install it onto a Phone 8 project.

Comments have been disabled for this content.