Improving Silverlight Application Performance
- The difference between synchronous and asynchronous programming techniques
- To download large objects asynchronously by using the WebClient
This lesson will introduce Silverlight's ability to asynchronously download large files and data from a server using the WebClient class.
Synchronous vs. Asynchronous Processing
Computers that contain a single processor are only capable of performing a single task at a time. Most laptops that are running Windows, for example, have a single processor (CPU) and are only capable of performing a single task on the computer at a time. If that is the case, how does an elaborate operating system like Windows seemingly perform many concurrent tasks as well as host multiple applications in memory simultaneously with each application also performing tasks? The answer is that the operating system manages the time that the processor allocates to performing each task very efficiently. The operating system allocates an incredibly small slice of the processor's time to each application and task that is in memory. The applications and tasks are then cycled through with each performing a small amount of work. The processor cycles through the applications and tasks very quickly as to give the illusion that multiple tasks are being performed simultaneously.
Each application that is loaded into memory is referred to as a process. Each process typically attempts to perform a single task and so each process is assigned a single thread of execution (a slice of the processor's time) to use to complete the task. Most code is written to perform a single task at a time and to complete the task at hand before continuing on to execute the next task. This type of processing is referred to as synchronous processing. In most scenarios, synchronously executing code is accomplished very quickly and will suffice. Additionally, in most scenarios, most tasks being performed in code are reliant upon the previous task being completed before the task can be performed. For example, when querying a database, the query cannot be executed until a connection to the database is open. Hence the database commands must be performed in a particular order and synchronous processing is a perfect fit.
However, occasionally tasks are performed in code that are not reliant upon other tasks to be completed first. When tasks that can be performed independently can be identified, it would increase performance if the task could be performed in parallel to other tasks being performed by the application. This is possible by intentionally writing code that spawns another thread of execution so that the process (application) is allocated more than one slice of the processor's time. If multiple tasks are performed in parallel by an application, the application is said to be multithreaded (utilizes more than a single thread to perform its work). When tasks are performed in parallel, the call in code from the initial thread that initiates a task to be performed on another thread doesn't have to wait around for the additional task to complete before continuing on. If it did wait for additional threads to complete their work, the tasks would still be performed in series and there would be no benefit to utilizing multiple threads of execution.
When an additional task is performed in parallel on a separate thread, it is referred to as asynchronous processing. Asynchronous processing is more complex than synchronous processing. When a task is performed synchronously, the code that initiated the synchronous task waits on the task to complete before continuing. However, when a task is performed asynchronously, the code that initiated the asynchronous task continues execution immediately and does not wait on the asynchronous task to complete. So what happens when the asynchronous task completes?
When code initiates an asynchronous task, it also directs the asynchronous task to execute a method or function (known as a callback method) once it completes its work.
Asynchronous processing is a perfect fit for time consuming tasks that can be performed independently. Asynchronous processing is being utilized in most of the recent Web technologies. For example, AJAX stands for Asynchronous JavaScript and XML. In AJAX, an asynchronous call is made to the server behind the scenes. The call is independent of the thread that is processing the Web page and interacting with the user, hence UI performance is increased and the user does not have to wait on the call to the server to complete but will see the results when the results are returned.
The WebClient Class
Silverlight includes a class that is used to directly download resources from a Web server, the WebClient class. The WebClient class was formerly called the HTTP Downloader. The WebClient is best suited to directly downloading larger resources from a Web server that may take time to download including images and media files. All networking calls made in Silverlight are asynchronous calls, hence all calls made by the WebClient are asynchronous. The code listing below is used to download an image from the server.
Notice that the code below includes snippets to illustrate downloading a single image as well as downloading a package of images. The WebClient class can be used to download a single file or multiple files. If multiple files are to be downloaded, they should first be packaged and compressed into a zip file. The WebClient class is capable of extracting a single file out of a zip file once the zip file has been downloaded.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ServiceModel;
using System.IO.IsolatedStorage;
using System.IO;
using System.Net;
using System.Windows.Resources;
using System.Windows.Media.Imaging;
namespace AthleteManager
{
public partial class Page : UserControl
{
UserInformation user = new UserInformation();
string password = "";
AthleteManager.AthleteInformation.AthleteServiceSoapClient svc;
WebClient downloader = new WebClient();
public Page()
{
InitializeComponent();
BasicHttpBinding bind = new BasicHttpBinding();
EndpointAddress endpoint = new EndpointAddress("http://localhost/AthleteManager/AthleteService.asmx");
svc = new AthleteManager.AthleteInformation.AthleteServiceSoapClient(bind,
endpoint);
downloader.OpenReadCompleted += new OpenReadCompletedEventHandler(downloader_OpenReadCompleted);
}
void downloader_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
{
// Display an image from a package.
//StreamResourceInfo photosDownloaded = new StreamResourceInfo(e.Result as
Stream, null);
//string photoToGrab = e.UserState.ToString();
//StreamResourceInfo photoStream = Application.GetResourceStream(photosDownloaded,
new Uri(photoToGrab, UriKind.Relative));
//BitmapImage bitmap = new BitmapImage();
//bitmap.SetSource(photoStream.Stream);
//bitmap.SetSource(e.Result);
//imgPhoto.Source = bitmap;
// Display a single image.
BitmapImage bitmap = new BitmapImage();
bitmap.SetSource(e.Result);
imgPhoto.Source = bitmap;
}
private void dgAthleteList_SelectionChanged(object sender, EventArgs e)
{
AthleteDisplayInfo athlete = (AthleteDisplayInfo)dgAthleteList.SelectedItem;
// verify that an athlete is selected.
if (athlete != null)
{
txtFirstName.Text = athlete.FirstName;
txtLastName.Text = athlete.LastName;
// download a package.
// downloader.OpenReadAsync(new Uri("Photos/Photos.zip", UriKind.Relative),
athlete.AthleteId.ToString() + ".JPG");
// download a single file.
downloader.OpenReadAsync(new Uri("Photos/" + athlete.AthleteId.ToString() +
".JPG", UriKind.Relative));
}
}
}
}
In the code above, an instance of the WebClient class is created. A callback method must be supplied prior to making the call. In this code, the OpenReadCompleted event is wired into the OpenReadCompletedEventHandler handler.
Lab: Improving Performance
In this lab, you will use the WebClient class to download content.
Download Images
In this exercise, you will use the WebClient class to dynamically download and display photos of the athletes.
- Modify the Silverlight XAML control. Add an Image control for displaying athlete photos. Ensure that the Image control has a Name assigned to it.
- Some photos exist in the sample application, however, you may choose to display photos of your liking. Zip up the images into a single file for the purposes of this exercise. Files may be downloaded individually or as a package.
- In the Silverlight control code behind, add code to the Selection Change event of the DataGrid so that the Image control is dynamically updated when the DataGrid selection changes.
- Create an instance of the WebClient class as a class member variable.
- Assign an event handler to the OpenReadCompleted event of the WebClient class instance in the class constructor.
- Make a call to the OpenReadAsync method in the DataGrid SelectionChange event handler. The call to the OpenReadAsync method for the example code is shown below.
downloader.OpenReadAsync(new Uri("Photos/Photos.zip", UriKind.Relative), athlete.AthleteId.ToString() + ".JPG");
- In the callback event handler for the OpenReadCompleted event, display the image returned by the call as shown in the code below:
void downloader_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { StreamResourceInfo photosDownloaded = new StreamResourceInfo(e.Result as Stream, null); string photoToGrab = e.UserState.ToString(); StreamResourceInfo photoStream = Application.GetResourceStream(photosDownloaded, new Uri(photoToGrab, UriKind.Relative)); BitmapImage bitmap = new BitmapImage(); bitmap.SetSource(photoStream.Stream); imgPhoto.Source = bitmap; }
- The resulting Silverlight control should resemble the following figure.
Lab: Improving Performance
In this lab, you will use the WebClient class to download content.
Exercise: Download Images
In this exercise, you will use the WebClient class to dynamically download and display photos of the athletes.
- Modify the Silverlight XAML control. Add an Image control for displaying athlete photos. Ensure that the Image control has a Name assigned to it.
- Some photos exist in the sample application, however, you may choose to display photos of your liking. Zip up the images into a single file for the purposes of this exercise. Files may be downloaded individually or as a package.
- In the Silverlight control code behind, add code to the Selection Change event of the DataGrid so that the Image control is dynamically updated when the DataGrid selection changes.
- Create an instance of the WebClient class as a class member variable.
- Assign an event handler to the OpenReadCompleted event of the WebClient class instance in the class constructor.
- Make a call to the OpenReadAsync method in the DataGrid SelectionChange event handler. The call to the OpenReadAsync method for the example code is shown below.
downloader.OpenReadAsync(new Uri("Photos/Photos.zip", UriKind.Relative), athlete.AthleteId.ToString() + ".JPG"); - In the callback event handler for the OpenReadCompleted event, display the image returned by the call as shown in the code below:
void downloader_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e) { StreamResourceInfo photosDownloaded = new StreamResourceInfo(e.Result as Stream, null); string photoToGrab = e.UserState.ToString(); StreamResourceInfo photoStream = Application.GetResourceStream(photosDownloaded, new Uri(photoToGrab, UriKind.Relative)); BitmapImage bitmap = new BitmapImage(); bitmap.SetSource(photoStream.Stream); imgPhoto.Source = bitmap; } - The resulting Silverlight control should resemble the following figure.
Improving Silverlight Application Performance Conclusion
In this lesson of the Silverlight tutorial, you
- Reviewed synchronous and asynchronous processing techniques
- Utilized the WebClient class