Windows 8 / Windows Phone Code Sharing: HttpWebRequest GetResponseAsync
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 looks 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!
Comments
Anonymous
January 03, 2013
Great article! Thank a lot, it was very helpful for my.Anonymous
January 24, 2013
Thanks ! Very useful !Anonymous
March 20, 2013
This will fail at runtime for Store if you ever need to set certain HTTP headers like content-length or user-agent - beware...