Async and Await for Http Networking on Windows Phone

Using async and await for executing long-running operations such as networking calls has many benefits: your code is much cleaner and easier to maintain, the result is automatically marshalled back to the originating thread so you don’t need to use Dispatcher.BeginInvoke to get back to the UI thread, and exception handling is simpler to implement. Many of the APIs in the Windows Runtime on both Windows 8 and and Windows Phone 8 use this pattern. It’s the future way of programming asynchronous operations.

Unfortunately, the networking APIs in Windows Phone 8 have not been upgraded to support async and await. On Windows 8 Store Apps by contrast, HTTP networking APIs have been completely re-implemented to offer only async and await methods: the WebClient API has been removed and replaced with a more performant API, HttpClient, and HttpWebRequest has been revamped and now only offers Async methods. However, by use of some extension methods, we can enjoy the goodness of async and await with the WebClient and HttpWebRequest APIs on Windows Phone 8. It will work with Windows Phone 7.5/7.8 projects as well, as long as you add a reference to the NuGet Microsoft.bcl.Async package which adds in async and Task support for Windows Phone OS 7.1.

First, let’s look at HttpWebRequest. The GetResponseAsync extension method for this allow you to write code that is exactly the same as for Windows 8 – great if you are porting code between the two. Kudos to Mathias Shapiro, colleague at Microsoft, who developed this!

using System.Net;
using System.Threading.Tasks;

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;
        }
    }

    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"; } }
    }
}

Using this, your HttpWebRequest calls now look something like this (don’t forget to add a using WinPhoneExtensions; import to the top of your class!):

        private async System.Threading.Tasks.Task GetSuppliers()
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://services.odata.org/Northwind/Northwind.svc/Suppliers");
            request.Method = HttpMethod.Get;
            request.Accept = "application/json;odata=verbose";

            try
            {
                HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();

                Debug.WriteLine(response.ContentType);
                // Read the response into a Stream object.
                System.IO.Stream responseStream = response.GetResponseStream();
                string data;
                using (var reader = new System.IO.StreamReader(responseStream))
                {
                    data = reader.ReadToEnd();
                }
                responseStream.Close();

                var feed = Newtonsoft.Json.JsonConvert.DeserializeObject<SupplierODataFeed>(data);
                SuppliersList.ItemsSource = feed.d.results;
            }
            catch (Exception ex)
            {
                var we = ex.InnerException as WebException;
                if (we != null)
                {
                    var resp = we.Response as HttpWebResponse;
                    var code = resp.StatusCode;
                    MessageBox.Show("RespCallback Exception raised! Message:{0}" + we.Message);
                    Debug.WriteLine("Status:{0}", we.Status);
                }
                else
                    throw;
            }
        }

…which is exactly the same as you would use in a Windows 8 store app.

We can do a similar thing for WebClient, though here the benefits are simply that the code you end up writing becomes so much cleaner. You don’t get the benefit of compatibility with Windows 8 since WebClient is not available on that platform.

I won’t list the code of the extension methods here, as it’s a bit lengthier than for HttpWebClient. Please download the samples attached to this post to get the extension methods code. When using the extension methods, you end up with lovely clean code like this:

string url = "https://api.twitter.com/1/statuses/user_timeline.xml?include_entities=true&include_rts=true&screen_name="
    + nameTextBox.Text + "&count=10";

var client = new WebClient();
string response = await client.DownloadStringTaskAsync(new Uri(url));

If you would like to watch me explaining this (and much, much more!) on video, check out the Networking video in the JumpStart series at http://aka.ms/i5qr0z.

Download the accompanying samples for the code!

3 thoughts on “Async and Await for Http Networking on Windows Phone

  1. besök webbplatsen

    Right after study several of the blog articles for the website at this point, and this i enjoy your current method of blogs. I bookmarked as their favorite it to my bookmark site collection and are examining back soon. Pls take into account my website too as well as inform me whatever you take into account.

    Reply
  2. aydiv

    Great post. In the exception handlers of your Async methods, you can also consider using the TrySetException method instead of TrySetResult so that the exception is propagated to the caller.

    catch (WebException webExc)
    {
    taskComplete.TrySetException(webExc);
    }

    Reply
  3. Olivia

    The write-up features verified beneficial to us.
    It’s very helpful and you’re simply obviously really educated in this area. You get popped our face to different thoughts about this specific subject along with intriguing and sound written content.

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *