I recently had the pleasure of speaking with some industry icons. We compared some RESTful jQuery code with the new HttpClient code from the WCF Rest Starter Kit Preview 2. The line by line comparison on the code was quite similar (the WCF REST team has done an excellent job with this API, I’m always amazed at how easy it is to use), the main difference was that the jQuery code was transmitting asynchronously. After our conversation, I decided to create these convenience extensions to give developers an API for using lambda expressions to call RESTful services asynchronously in .NET.
Download
In this application I use the jQuery code from my Intro to jQuery presentation and the Live Search WPF Application. The first method I wrote was the GetAsync extension, and after realizing how simple it was I created this entire Extension Library. Additionally, since all the code fit nicely into a single class I’m going to publish the code as a single cs file. As usual, I’m also including the Sample application for download.
HttpAsyncMethodExtensions.cs (12.1KB)
HttpClientExtensions Sample WPF Application (Compressed Zip, 13.1KB)
Code Comparison
The goal of this API was to mimic the jQuery AJAX code that I had previously written. Here is a actual ajax portion of the jQuery code that retrieves some google search results:
$(document).ready(function() { $('.getGoogle').click(function(e) { // Prevent the event and Set Loading Message e.preventDefault(); $('.results .noResults').html('Loading...'); // Generate the google Url var googleUri = "http://www.google.com/search?q=" + $('.searchText').val(); // Send Async GET call $.get(googleUri, {}, function(html) { // Parse result and create placeholder var google = $(html); var ul = $('<ul />'); // find links from results $('.g .r .l', google).each(function() { // create the list item, generate the list item, and add it to the placeholder ul.append($('<li />') .append($(this).clone().removeAttr('onmousedown')) // this.clone() clones the google link ); }); $('.results').append(ul).find('.noResults').remove(); }); }); });
Using this jQuery code as a guide I created the usage code first:
private void Search_Click(object sender, RoutedEventArgs e) { // Set Loading Message this.Items.Clear(); this.Items.Add("Loading ..."); // Generate Google Uri const string googleApiUrl = "http://ajax.googleapis.com/ajax/services/search/web?v=1.0&q={0}"; var uri = string.Format(googleApiUrl, this.SearchText.Text); // Create Client and Send Asynchronous GET var client = new HttpClient(); client.GetAsync(uri, (s, r) => { // Clear Loading Message this.Items.Clear(); // Parse Results var results = r.Response.Content.ReadAsJsonDataContract<googleResults>(); // Find and add the results this.Items.AddRange(results.responseData.results.Cast<object>()); }); }
I tried to keep the two samples consistent, and as you can see the HttpClient code is 5 lines smaller than its jQuery counterpart. Unfortunately, these samples are not identical implementations. For instance, one client is a web browser and the other is a WPF application. Additionally, both projects have additional code, behind the scenes. But since the goal was to create a similar API I think it works.
HttpClient Extension Methods
What you may not know, is that the HttpClient gains most of its leverage from extension methods. The core functionality of the HttpClient is in its Send method. In the existing API, the Get, Post, Put, Delete methods are extension methods which simple call Send. Using that same concept, here is a GetAsync extension method to the HttpClient:
public static class HttpAsyncMethodExtensions { public static void GetAsync(this HttpClient client, string uri, EventHandler<sendCompletedEventArgs> completed) { // register callback client.SendCompleted += completed; // call SendAsync var message = new HttpRequestMessage(HttpMethod.GET.ToString(), uri); client.SendAsync(message); } }
The HttpClientAsyncExtensions Library, that is downloadable above, contains the full implementation of these extension methods for SendAsync, GetAsync, PostAsync, PutAsync, DeleteAsync, and HeadAsync. There are also a few overloaded helper methods to avoid repeating code.
Conclusion
I think its great that we have the ability to choose between synchronous and asynchronous processing of remote calls. Unfortunately, the amount of code required to perform these tasks is often quite different.
We’ve all seen applications that block the UI thread while executing a long running task synchronously. I’m not sure if this is because of the tools or because of a lack of knowledge around asynchronous programming. Either way, developers often feel that asynchronous programming is difficult.
I’m hoping that these extension methods will show that this doesn’t have to be the case, and that we can actually make remote services calls asynchronously with very little code.