Portable class libraries and fetching JSON
- by Jeff
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.