Walkthrough: Getting Started with Async in WPF

Introduction

The new features previewed in the Visual Studio Async CTP (SP1 Refresh) enable you to write asynchronous programs with only a small fraction of the difficulty inherent in the existing .NET Framework approaches. You can write asynchronous code that looks very much like synchronous code, and let the compiler handle the complications of callback functions or continuation code.

This walkthrough begins with a demonstration of a synchronous WPF application that finds and displays all the movies in the Netflix catalog that were released in a specified year. The walkthrough then shows how to change the synchronous solution to an asynchronous solution by using the CTP features.

The application uses the Open Data Protocol (OData) API to query the Netflix catalog for movies that were released in the year that you specify. For more information about OData, see the Netflix website.

Prerequisites

To complete this walkthrough, you must have Microsoft Visual Studio 2010 with SP1, and the Async CTP installed on your computer.

To open the Async CTP splash page

  1. You can return to the CTP splash page at any time from Windows Explorer. Go to My Documents\Microsoft Visual Studio Async CTP\Documentation.
  2. Double-click Readme.hta.
  3. Alternatively, click Start, All Programs, Visual Studio Async CTP, and then Async Readme.

To test a synchronous version of the application

  1. On the Async CTP splash page, click C# or VB in the Getting Started section to open the project in Visual Studio.

  2. Press Ctrl+F5 to run the application.

  3. The following window appears.

  4. Type a year in the Release year box and then click the Search button. The application searches the Netflix catalog for movies that were released in that year, displays the "box art" associated with each title, and shows the total number of matches.

  5. Enter a recent year and then click the Search button again. Notice the following behavior in the synchronous solution:

    • The image does not change until the end of the program. The results panel is not cleared, no new box art is displayed, and the status text in the upper-right corner does not report subtotals as the search progresses. You see the number of titles found only at the end.
    • Worse, while the program is running, you cannot get its attention. You cannot resize, move, or minimize the window, and you cannot scroll. You cannot use the Close button (the x in the red field in the upper-right corner) to end the program if you get tired of waiting for results. Even closing Visual Studio has no effect. You wait.
    • If the Netflix website is down for some reason, the UI freezes while the program waits for a time-out and, again, you wait.

To start the conversion to an asynchronous solution by adding a reference for the CTP

  1. On the Project menu, click Add Reference. The Add Reference dialog box appears.
  2. On the Browse tab, navigate to the download location for the Async CTP samples. By default, the download location is My Documents\Microsoft Visual Studio Async CTP\Samples.
  3. Click AsyncCtpLibrary.dll and then click OK.

To convert the code to an asynchronous application

As you saw in procedure "To test a synchronous version of the application," the application searches the Netflix catalog for films that were released in a specified year. It displays the associated box art for each movie. The box art is linked to the Netflix webpage for that movie.

Two methods in the application are involved in retrieving information from the web, and these are the methods that you need to change to convert from a synchronous solution to an asynchronous solution.

  • LoadMovies sets the stage and then calls QueryMovies repeatedly to fetch XML data for 10 (the value of the pageSize variable) movies at a time. It calls DisplayMovies to display the results.
  • QueryMovies accesses the web to retrieve information about the next 10 movies. From each entry in the results, it picks out the fields that the display uses: the title, the URL, and the box art.

The following steps convert these two synchronous methods to asynchronous methods. When you make each change, an error message guides you to the next one.

  1. Right-click MainPage.xaml in Solution Explorer, and then click View Code to open the code in the Code Editor.

  2. QueryMovies is the method that directs the downloading of information from the web, so it is the heart of the asynchronous solution. The synchronous solution uses the WebClient method DownloadString to accomplish the download. The first step of the conversion is to change from DownloadString to an asynchronous download method. IntelliSense shows you the following choices. In Visual Basic, click the All tab.

    Choose the last one, DownloadStringTaskAsync, an asynchronous, task-based WebClient extension method that is provided by the Async CTP. If you do not see the method in the drop-down list, just type it in.

  3. To enable the call to the asynchronous method DownloadStringTaskAsync, you have to make QueryMovies an asynchronous method.

    First, add await in C# or Await in Visual Basic in front of the call to DownloadStringTaskAsync, as shown in the following code.

// C# string data = await client.DownloadStringTaskAsync(new Uri(url));


' Visual Basic Dim data As String = Await client.DownloadStringTaskAsync(New Uri(url))


DownloadStringTaskAsync returns a task, and await or Await is applied to the task. You could replace the previous single-line assignments with the following two lines of code to make the conversion explicit.

// C#
// This code is not part of the solution.
Task<string> theTask = client.DownloadStringTaskAsync(new Uri(url));
string data = await theTask;

' Visual Basic
' This code is not part of the solution.
Dim theTask As Task(Of String) = client.DownloadStringTaskAsync(New Uri(url))
Dim data As String = Await theTask

  1. Next, add the modifier async in C# or Async in Visual Basic to the definition of QueryMovies. You can use the await or Await keyword only when the immediately enclosing method or lambda expression has the async or Async modifier.
// C# async Movie[] QueryMovies(int year,int first,int count) { var client = new WebClient();


' Visual Basic Async Function QueryMovies(year As Integer, first As Integer, count As Integer) As Movie() Dim client As New WebClient


  1. The return type of an asynchronous method must be void, Task, or Task<T> in C#. In Visual Basic, the method must be a Sub, or be a Function that returns Task or Task(Of T). Change the return type from Movie[] to Task<Movie[]> in C#, or from Movie() to Task(Of Movie()) in Visual Basic.
// C# async Task<Movie[]> QueryMovies(int year,int first,int count)


' Visual Basic Async Function QueryMovies(year As Integer, first As Integer, count As Integer) As Task(Of Movie())


  1. Add the following using directive or Imports statement at the top of the code file to establish the definition of type Task.
// C# using System.Threading.Tasks;


' Visual Basic Imports System.Threading.Tasks


  1. By convention, asynchronous methods should be given names that end in "Async". Change method name QueryMovies to QueryMoviesAsync.
// C# async Task<Movie[]> QueryMoviesAsync(int year,int first,int count)


' Visual Basic Async Function QueryMoviesAsync(year As Integer, first As Integer, count As Integer) As Task(Of Movie())


  1. The conversion of QueryMovies to QueryMoviesAsync is complete. Next, apply the same process to LoadMovies, which calls the now asynchronous method QueryMoviesAsync. For this method, you do not have to change the return type because the method does not return a meaningful value.

    First, change the name of the method that LoadMovies calls from QueryMovies to QueryMoviesAsync.

// C# var movies = QueryMoviesAsync(year,imageCount,pageSize);


' Visual Basic Dim movies = QueryMoviesAsync(year,imageCount,pageSize)


  1. Second, because QueryMoviesAsync is an asynchronous method, add await in C# or Await in Visual Basic in front of the call.
// C# var movies = await QueryMoviesAsync(year,imageCount,pageSize);


' Visual Basic Dim movies = Await QueryMoviesAsync(year,imageCount,pageSize)


  1. Third, add the async or Async modifier to the definition of LoadMovies.
// C# async void LoadMovies(int year)


' Visual Basic Async Sub LoadMovies(year As Integer)


  1. Finally, use Refactor in C# or Rename in Visual Basic to change LoadMovies to LoadMoviesAsync.
// C# async void LoadMoviesAsync(int year)


' Visual Basic Async Sub LoadMoviesAsync(year As Integer)


That's it! You called a different WebClient method, added a using directive or Imports statement, added a few keywords, renamed two methods, and modified a return type, and you have an asynchronous solution.

To run and test the program

  1. Press Ctrl+F5 to run the application.
  2. Repeat the tests in steps 4 and 5 from procedure "To test a synchronous version of the application." Notice the improvements that asynchronous behavior provides:
    • The results do not all occur at the same time at the end of the program. For example, the display panel clears as soon as you click the Search button, and the box art is not all displayed at the same time. You begin to see results as soon as you click the Search button.
    • You can move or resize the window, or scroll in it while the process runs.
    • You can end the search at any time by clicking the Close button (the x in the red field in the upper-right corner).
    • The progress text updates during the search, showing you how many matching titles have been found so far.
    • You can click a box art image and go to the Netflix page for that movie without waiting for the entire search to complete.
    • Most importantly, if the Netflix website is down, the UI remains responsive.

The new features introduced in the Async CTP enable you to have all the benefits of asynchronous programming with almost none of the pain. Your code still looks like synchronous code, but you can specify asynchronous behavior wherever you want it -- and you can do so in an easy, intuitive manner.

For links to white papers, language specifications, and blog entries that contain additional information, see Asynchronous Programming for C# and Visual Basic or the Documentation section of the Async CTP splash page.