Exercise 4: Async Library Refactoring

In this exercise, you will refactor the solution in order to move the asynchronous logic to a class library, using the proper naming conventions for asynchronous methods. Additionally, you will improve the performance by avoiding the marshal of the asynchronous results back to the User Interface (UI) thread when it is not necessary.

Task 1 – Creating an Asynchronous Class Library

  1. Open Visual Studio 11 and load AsyncLab-Ex4-Begin.sln solution located in the Source\[CS|VB]\Ex4-Refactoring\Begin folder of this lab. You can also continue working with the solution you’ve obtained after completing Exercise 3.
  2. Create a new Class Library project into the same solution. Name the new project AsyncLabLibrary. Then, delete Class1 (created by default).
  3. Add a reference to PresentationCore and System.Net.Http.
  4. Copy LinkInfo class from the AsyncLab project into the AsyncLabLibrary library, and then delete the original LinkInfo file from the AsyncLab project.
  5. Only for C# projects: rename the namespace in the LinkInfo.cs file from “AsyncLab” to “AsyncLabLibrary”.
  6. Add a reference to the AsyncLabLibrary library in the AsyncLab project.
  7. In AsyncLabLibrary project, add a new class and name it Downloader.
  8. Only for C# projects: set the Downloader class access modifier to Public.
  9. Include the following namespace directives:

    (Code Snippet – Async Lab - Ex04 - References - CS)

    C#

    using System.Net.Http; using System.Text.RegularExpressions; using System.Threading; using System.Windows.Media;

    (Code Snippet – Async Lab - Ex04 - References - VB)

    Visual Basic

    Imports System.Net.Http Imports System.Text.RegularExpressions Imports System.Threading Imports System.Windows.Media

Task 2 – Refactoring the Project

  1. Open MainWindow.xaml.cs or MainWindow.xaml.vb from the AsyncLab project.
  2. Move the DownloadItemAsync, PollItem and GetTitle methods from the MainWindow.xaml.cs or MainWindow.xaml.vb file to the Downloader class.
  3. Rename the DownloadItemAsync method to DownloadItemAsyncInternal. If you are working in C#, use Visual Studio Refactoring to rename any reference to the method.
  4. Rename the PollItem method to PollItemAsync.If you are working in C#, use Visual Studio Refactoring feature to rename any reference to the method. Otherwise, rename the PollItem method call to PollItemAsync in the DownloadItemAsync method.
  5. Create a DownloadItemAsync public method. The method will receive an URI and a CancellationToken to support cancellation and call DownloadItemAsyncInternal.

    (Code Snippet – Async Lab - Ex04 - DownloadItemAsync - CS)

    C#

    public static Task<LinkInfo> DownloadItemAsync(Uri itemUri, CancellationToken cancellationToken) { if (itemUri == null) { throw new ArgumentNullException("itemUri"); } return DownloadItemAsyncInternal(itemUri, cancellationToken); }
    
    

    (Code Snippet – Async Lab - Ex04 - DownloadItemAsync - VB)

    Visual Basic

    Public Shared Function DownloadItemAsync(ByVal itemUri As Uri, ByVal cancellationToken As CancellationToken) As Task(Of LinkInfo) If itemUri Is Nothing Then Throw New ArgumentNullException("itemUri") End If Return DownloadItemAsyncInternal(itemUri, cancellationToken) End Function
    
    FakePre-393605f6013b4c81b9c137325f6140d2-a717ec1b71524c01815bdcb6a75ec213
    

  6. Create an overload method for DownloadItemAsync without the cancellation token parameter.

    (Code Snippet – Async Lab - Ex04 - DownloadItemAsync No Cancellation - CS)

    C#

    public static Task<LinkInfo> DownloadItemAsync(Uri itemUri) { return DownloadItemAsync(itemUri, CancellationToken.None); }

    (Code Snippet – Async Lab - Ex04 - DownloadItemAsync No Cancellation - VB)

    Visual Basic

    Public Shared Function DownloadItemAsync( ByVal itemUri As Uri) As Task(Of LinkInfo) Return DownloadItemAsync(itemUri, CancellationToken.None) End Function
    
    

  7. Modify the DownloadItemAsyncInternal method to call the ConfigureAwait method at the end of SendAsync call, and set its parameter to false. To do that, replace the line that performs a GetAsync call with the following code:

    (Code Snippet – Async Lab - Ex04 - DownloadItemAsyncInternal ConfigureAwait- CS)

    C#

    var message = new HttpRequestMessage(HttpMethod.Get, itemUri); var response = await httpClient.SendAsync( message, cancellationToken).ConfigureAwait(false);

    (Code Snippet – Async Lab - Ex04 - DownloadItemAsyncInternal ConfigureAwait - VB)

    Visual Basic

    Dim message = New HttpRequestMessage(HttpMethod.Get, itemUri) Dim response = Await httpClient.SendAsync( message, cancellationToken).ConfigureAwait(False)

    Note:
    When a call that uses the await keyword completes, it marshals the continuation (the remainder of the method’s execution) back to the UI thread. If this is not needed, call ConfigureAwait(false) for improved performance.

  8. Modify the PollItemAsync method to call ConfigureAwait at the end of the SendAsync call, and set its parameter to false.

    (Code Snippet – Async Lab - Ex04 - PollItem ConfigureAwait- CS)

    C#

    await Task.Delay(5000, cancellationToken);
    FakePre-fe19d3f3a32d4a15b07a04ccae051313-3b09fc99686c4ba5929a6a487afa18e0FakePre-290000ef0eb14a6fabc0aa8936afaa7b-a41da5afba4d4124aba93569dfd0da76var response = await httpClient.SendAsync(requestMessage, cancellationToken).ConfigureAwait(false);FakePre-b5f6ff310775455c9dfdef948f310191-6320082218a149feb642c2d8514e9b5e

    (Code Snippet – Async Lab - Ex04 - PollItem ConfigureAwait - VB)

    Visual Basic

    Await Task.Delay(5000, cancellationToken)
    FakePre-c0bafba124f1477e9a60bd3db1c8677a-d1198dfb4af04aeab47df8358f33b491Dim response = Await httpClient.SendAsync(requestMessage, cancellationToken).ConfigureAwait(False)

  9. Open MainWindow.xaml.cs or MainWindow.xaml.vb code-behind file and import the AsyncLabLibrary namespace.

    (Code Snippet – Async Lab - Ex04 - References dll - CS)

    C#

    using AsyncLabLibrary;

    (Code Snippet – Async Lab - Ex04 - References dll - VB)

    Visual Basic

    Imports AsyncLabLibrary

  10. In the startButton_Click method, replace the ListBox polling code to call the new DownloadItemAsync method from the downloader library.

    (Code Snippet – Async Lab - Ex04 - DownloadItemAsync Call - CS)

    C#

    listBox1.ItemsSource = await Task.Run(() => { return Task.WhenAll(from uri in uris select Downloader.DownloadItemAsync(new Uri(uri), cancellationToken.Token)); });

    (Code Snippet – Async Lab - Ex04 - DownloadItemAsync Call - VB)

    Visual Basic

    listBox1.ItemsSource = Await Task.Run(Async Function() Return Await Task.WhenAll( _ From uri In uris _ Select Downloader.DownloadItemAsync( New Uri(uri), cancellationToken.Token)) End Function)

  11. Press F5 to run the application. You will notice no difference from the client side. The application UI is responsive, even while the links are being downloaded and polled. ConfigureAsync provides a performance improvement, as it does not wait for the data to be marshaled back to the UI thread.