Shawn Wildermuth's Rants and Raves

Thanks for visiting my blog! See more about me here: About Me

WebClient vs. WebRequest in Silverlight 2
WebClient vs. WebRequest in Silverlight 2
September 27, 2008

Silverlight Logo
When making web requests in Silverlight 2, its easy to start with the simple WebClient class. In fact, it supports making simple requests (DownloadStringAsync and OpenReadAsync) as well as uploading through the class. On the other hand there are some that swear by the WebRequest route. What’s the big difference?

Let’s start with WebRequest. The pattern for WebRequest is to call WebRequest.Create:

Uri url = new Uri("http://localhost:8889/Silverlight.js", UriKind.Absolute);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);;

Notice that we are actually using a HttpWebRequest object and casting the return value of the Create call. In reality this object is a BrowserHttpWebRequest object. This class represents a web request in Silverlight 2 (since all requests are actually routed through the browser’s networking stack). The reason for this is to make sure that any requests are part of the page.  This means that when you make a request in Silverlight 2 it is bringing with it the same Session ID and cookies.  This also means that for large sized requests, the user may cancel the request.

To execute the request, we need to get a WebResponse object that contains our results of the request. To do this, ordinarily you would call the HttpWebRequest’s BeginGetResponse method:

req.BeginGetResponse(new AsyncCallback(WebComplete), req);

This method specifies that you create an AsyncCallback object that describes the callback once the request is complete.  The WebComplete object in the AsyncCallback is actually the method to call (though you could use a delegate or lambda here):

void WebComplete(IAsyncResult a)
{
  HttpWebRequest req = (HttpWebRequest)a.AsyncState;
  HttpWebResponse res = (HttpWebResponse)req.EndGetResponse(a);
  Dispatcher.BeginInvoke(() => status.Text = "Downloading...Done.");
}

Note that we’re retrieving the request from the AsyncState and then calling EndGetResponse to complete the operation. The most important thing to understand inside this callback is that it does not happen on the UI thread so any calls to update the UI will result in InvalidThreadAccessExceptions. Typically this means using the Dispatcher to call the UI thread as necessary (as shown). In addition, the response contains a stream that contains the results of the request. To retrieve the data, you need to write code to dig it out of the stream as necessary…not hard, but another step.

In contrast, the WebClient class performs this operation very differently. First, it supports two different request styles: DownloadString and OpenReadDownloadString support the ability to retrieve a string with the contents of the request. The OpenRead style returns a Stream instead. This way you can decide if you need a simple way to retrieve just a string, otherwise you can use the tried and true way of consuming a Stream.

Another change is the WebClient class uses events not AsyncCallbacks to complete the asynchronous model.  The events and execution start of each of the styles are paired up with Completed events and Async execution methods. For example, to make a request with the WebClient with the DownloadString style:

WebClient client = new WebClient();
client.DownloadStringCompleted += 
  new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
client.DownloadStringAsync(new Uri("/Silverlight.js", UriKind.Relative));

The other big difference is that the WebClient class handles the context switch for the user. What this means is that when the event is fired, it is always called on the UI thread. So your event handling code can update the UI directly as so:

void client_DownloadStringCompleted(object sender, 
                                    DownloadStringCompletedEventArgs e)
{
  status.Text = "Downloading...Done.";
}

So what’s the verdict?  There is none. They both are fine to use.  In fact, under the covers the WebClient class uses the BrowserHttpWebRequest class so that it does not matter. If you find the WebClient class easier to use, go ahead. But if you are already familiar with the HttpWebRequest-style classes and AsyncCallback objects, continue to do what you’re comfortable with. Just understand the differences between these workhorses of Silverlight 2.

What do you use?