I’m working on building helpers for sharing code between Windows 8 (Windows Store) and Windows Phone. Keep an eye on my github for additional updates.
I love the new async-await model in .NET 4.5 (and also in .NET 4.0 if you’re interested). One of the most exciting uses of it (for me) is the ability to do HTTP calls and simply wait for the result. Instead of setting up event handlers and custom events I can write a service that works like
Tweet myTweet = await GetTweet(tweetID);
and just wait for the result to come back. If I’m writing a service call for a Windows Store app and I use HttpWebRequest to make my call, the writing this call is very simple
public async Task<string> GetMyData(string urlToCall) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlToCall); request.Method = HttpMethod.Get; HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync(); using (var sr = new StreamReader(response.GetResponseStream())) { return sr.ReadToEnd(); } }
and then I can run this as an await-able method.
But if we want to share code between my Windows 8/Windows Store app and my Windows Phone app, the problem comes where this await-able GetResponseAsync method isn’t available in Windows Phone. We’re stuck using the old event based model.
So I threw together these extensions for solving that problem. These are actually two problems here:
- There is no awaitable GetResponseAsync() in Windows Phone’s version of HttpWebRequest
- There is no HttpMethod enum in Windows Phone. We have to use a string instead.
So I wrote the following so we can write the same http service calls one time and share it across our Windows 8 and Windows Phone projects.
First, an extension for Windows Phone HttpWebResponse:
namespace WinPhoneExtensions { public static class HttpExtensions { public static Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest request) { var taskComplete = new TaskCompletionSource<HttpWebResponse>(); request.BeginGetResponse(asyncResponse => { try { HttpWebRequest responseRequest = (HttpWebRequest)asyncResponse.AsyncState; HttpWebResponse someResponse = (HttpWebResponse)responseRequest.EndGetResponse(asyncResponse); TaskComplete.TrySetResult(someResponse); } catch (WebException webExc) { HttpWebResponse failedResponse = (HttpWebResponse)webExc.Response; taskComplete.TrySetResult(failedResponse); } }, request); return taskComplete.Task; } } }
This takes the event-based model that we use in Windows Phone and encapsulates it in a Task so we can use it in an await-async manner.
Second, I added this class to the same namespace to deliver an HttpMethod class that works with the same code that we would use in Windows 8.
public static class HttpMethod { public static string Head { get{return "HEAD";} } public static string Post { get{return "POST";} } public static string Put { get{return "PUT";} } public static string Get { get{return "GET";} } public static string Delete { get{return "DELETE";} } public static string Trace { get{return "TRACE";} } public static string Options { get{return "OPTIONS";} } public static string Connect { get{return "CONNECT";} } public static string Patch { get{return "PATCH";} } }
Now, to use this with our code above, we only need to add:
#if WINDOWS_PHONE using WinPhoneExtensions; #endif
to our class that makes the Http call and we’re good to go!