Asynchronously Download Content In Silverlight 2

One of the great new features within the world of entertainment has been the addition of on-demand content. This enhancement gives the opportunity to enjoy audio or video elements at your convenience. And although this convenience may be nice in the living room, it’s often viewed as a requirement within web-based applications. With this thought in mind, Silverlight gives you the ability to easily retrieve on-demand content with one simple class: WebClient.

The System.Net.WebClient class acts as a special utility class that enables you to asynchronously download content. This class is different from the other networking and communication options in Silverlight in two ways. First, this class provides the ability to monitor the progress of a download request. At the same time, this class uses an event-based model for its API instead of a delegate model used by the other networking and communication options in Silverlight. Regardless, the content you request may be in the form of an image, audio, or video file. Alternatively, this content may be a compressed package of files or even other application modules. Either way, the WebClient class can be used to dynamically retrieve all kinds of content on-demand.

To retrieve items on-demand, you must first request the content. Sometimes, this content can be fairly large in size. Because of this, you must take into consideration how to manage larger download requests. Finally, once a download request has completed, you must decide how you want to load the content. Let’s look at the details associated with each of these steps. This content is pulled from the book Silverlight 2 in Action, which provides deep and rich content to help you develop Silverlight 2 applications quickly.

Requesting content

The WebClient class empowers you to request content through two similar, but different, methods. These methods are DownloadStringAsync and OpenReadAsync. The DownloadStringAsync method is intended to be used with string-related data, whereas the OpenReadAsync method is designed to work with binary content. Throughout this section, we’ll cover both approaches for requesting content.

Requesting String Content

The DownloadStringAsync method can be used to download string-related content. This content includes things such as JSON, XML, or open text. Regardless of the kind of data, the DownloadStringAsync method will start the download process. This process will run asynchronously until the content is downloaded or an error has occurred. The code to kick off this download process is demonstrated in snippet 1.

Snippet 1

public void RequestStringContent()
{
   Uri uri = new Uri("http://www.somedomain.com/rss.xml");    (1)
   WebClient webClient = new WebClient();
   webClient.DownloadStringAsync(uri);                        (2)
}

This snippet shows how to request string-based content using the WebClient. The first step is to define a Uri that references the content to download (1). This Uri is used later as a parameter to the DownloadStringAsync method (2). This method is responsible for starting the download of the content referenced by the Uri. This content will be retrieved using the HTTP GET method of retrieval. This retrieval method is also used when requesting binary content.

Requesting Binary Content

The OpenReadAsync method can be used to request binary content. This kind of content includes things such as compressed files (.zip files), application modules (other .dll files), and media files. These types of files can be downloaded asynchronously using the OpenReadAsync method as shown in snippet 2.

Snippet 2

public void RequestStreamContent()
{
   Uri uri = new Uri("http://silverlightinaction.com/video3.wmv");
   WebClient webClient = new WebClient();
   webClient.OpenReadAsync(uri);                               (1)
}

This snippet shows how to request binary content using the WebClient class. This process closely resembles the approach used for downloading string content. The only difference is that, for binary content, you should use the OpenReadAsync method (1). Regardless of the type of content, it’s important to consider the size of the data. Generally, larger downloads need to provide additional functionality to create a valuable user experience. This feature is part of managing larger download requests.

Managing larger download requests

After a download request has been sent, you need to know when the download has completed. This will be discussed later in this article. For now though, you will see how to keep a user informed as a download progresses. This involves monitoring the progress of a download with the DownloadProgressChanged event. If this download is taking too long, a user may want to cancel the request. For this type of functionality, you can use the CancelAsync method. Both these items are discussed throughout this section.

Monitoring the Progress

The DownloadProgressChanged event empowers you to keep track of the advancement of a download. As a download progresses, the DownloadProgressChanged event will fire repeatedly until all the requested content has been retrieved. When this event is triggered, a DownloadProgressChangedEventArgs parameter is passed to the associated event handler. This parameter gives you access to the details associated with the overall progress of a download. The information provided by the DownloadProgressChangedEventArgs type is demonstrated in snippet 3.

Snippet 3

void webClient_DownloadProgressChanged(object sender,
   DownloadProgressChangedEventArgs e)
{
   StringBuilder sb = new StringBuilder();
   sb.Append(e.BytesReceived + " of ");                        (1)
   sb.Append(e.TotalBytesToReceive + " bytes received");       (2)
   myTextBlock.Text =   sb.ToString();
}

This snippet demonstrates an event handler for the DownloadProgressChanged event. This event handler uses the DownloadProgressChangedEventArgs parameter to build a string informing the user of a download’s progress. This string is created by using the two progress-related properties: BytesReceived(1) and TotalBytesToReceive (2).

You may want to show how large a download is. You can accomplish this by using the TotalBytesToReceive property, which is a long value that represents the total number of bytes of the requested content. As this content is retrieved, you can see how many bytes have already been downloaded through the BytesReceived property. This property is a long that gives you the total number of bytes that have been downloaded.

The BytesReceived property, along with the TotalBytesToReceive property, can be valuable in providing updates that can help calm an anxious user. These updates can also be useful in helping a user decide to cancel a download request.

Canceling a Download Request

Providing a user with information about the overall progress of a download can remove the pain of the unknown, but longer downloads can still create an unpleasant experience for a user. If a download isn’t a required part of an application, you may want to empower your users with the option to cancel it by calling the CancelAsync method. This method is demonstrated in snippet 4.

Snippet 4

WebClient webClient = new WebClient();
protected void cancelButton_Click(object sender,
   RoutedEventArgs e)                                          (1)
{
   if (webClient.IsBusy)                                       (2)
   {
      webClient.CancelAsync();                                 (3)
   }
}

This snippet shows an event handler for an imaginary Cancel button (1). This event handler cancels a download by using the WebClient class’s CancelAsync method (3). This method can be used to halt a web request already in progress. In this particular example, you explicitly check to see if a download is in progress by using the IsBusy property. This property returns a bool value (2) that flags whether or not a download is in progress. In reality, this additional check isn’t needed, but it can be used to improve the performance of your code. You can also improve the maintainability of your code by declaring a WebClient as an instance variable.

As you’ve probably noticed, the CancelAsync method and IsBusy properties are members of the WebClient class, so it’s recommended that you define your WebClient class instance as a member of the class associated with your download. This approach is slightly different than that used in snippets 1 and 2. But, by doing this, you have the flexibility to cancel a download request in any way needed. In addition, it gives you the ability to reuse the event handlers associated with a WebClient. Either way, it is important to recognize that a WebClient instance can only handle one download request at a time, so you may want to consider using the IsBusy property before you start a download. Once this download has started and is completed, you must then decide how to load the content.

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read