Exercise 3: Polling and Cancellation

In this exercise, you will add additional features to the application. First, you will introduce the ability to cancel the work that is processing in the background. Then, you will add the ability to poll the content of each of the links retrieved and check for modifications. In that case, you will notify the user by changing the link color in the ListBox.

Task 1 – Adding the Cancellation Feature

In this task, you will implement the cancellation feature in the application in order to terminate ongoing tasks.

  1. Open Visual Studio 11 and load the AsyncLab-Ex3-Begin.sln solution located in the Source\[CS|VB]\Ex3-PollingAndCancellation\Begin folder of this lab. You can also continue working with the solution you’ve obtained after completing Exercise 2.
  2. Open MainWindow.xaml.cs or MainWindow.xaml.vb and import the System.Threading namespace.

    C#

    using System.Threading;

    Visual Basic

    Imports System.Threading

  3. Define a class variable to create the cancellation token.

    (Code Snippet – Async Lab - Ex03 - Cancellation Token - CS)

    C#

    public partial class MainWindow : Window
    FakePre-d1aa6c30e95b4647829a35e77a470b6e-b418c9480abe4e29b03f87aaedb4ebc7 private CancellationTokenSource cancellationToken;

    (Code Snippet – Async Lab - Ex03 - Cancellation Token - VB)

    Visual Basic

    Class MainWindow
    Private cancellationToken As CancellationTokenSource

  4. Modify the DownloadItemAsync method to receive a CancellationToken parameter.

    C#

    private static async Task<LinkInfo> DownloadItemAsync( Uri itemUri, CancellationToken cancellationToken)
    {

    Visual Basic

    Private Shared Async Function DownloadItemAsync(ByVal itemUri As Uri, ByVal cancellationToken As CancellationToken) As Task(Of LinkInfo)

  5. Create a new instance of the cancellation token inside the startButton_Click event handler.

    (Code Snippet – Async Lab - Ex03 - Cancellation Token Instance - CS)

    C#

    private async void startButton_Click(object sender, RoutedEventArgs e)
    FakePre-4a10452bb2fa431a827729d33a2aaf59-ea4da44e722249e6bcff05dd97e59cc3 cancellationToken = new CancellationTokenSource();FakePre-baca74d635e14b6887be3b535b943202-ee9078fea7d0423482f78ce2feddbb0a

    (Code Snippet – Async Lab - Ex03 - Cancellation Token Instance - VB)

    Visual Basic

    Private Async Sub startButton_Click(sender As System.Object, 
    FakePre-d4af7471bcf94e28b2f3e4c3572cc30e-b1006ab7cb604dadbc270397332c3450FakePre-02f61911905146299c1d5fdf3aee74fe-beb9f8eafeab4c919a34a9c5ba63b08f cancellationToken = New CancellationTokenSource()FakePre-4a2ebccd1a4e4d29a8bdb6e7a0914fe5-d880dc5abed84de8aff1b8e727346da7

  6. In the startButton_Click method, modify the HttpClient call to include a cancellation token. Then, replace the GetAsync call with a SendAsync call, which supports cancellation tokens.

    (Code Snippet – Async Lab - Ex03 - StartClick with CancellationToken - CS)

    C#

    try
    FakePre-329be8ad65604494a79221d03e760dd9-4ec92160bad04b3abc0976f5697a764e HttpRequestMessage message = new HttpRequestMessage( HttpMethod.Get, "http://msdn.microsoft.com"); var response = await new HttpClient().SendAsync(message, cancellationToken.Token);FakePre-fb146b823bbf4454973abde2ec175367-98350d4ef2bb4728b8f5634f564f3b9dFakePre-9943207bc9bd4bf4b4c36cd55ae7f28b-9efb011a7ff44461aa6cc99018ee3807FakePre-31546d3109184555bf525e155c9a13aa-a32ac25494fb486aa0d9eee7045bc637

    (Code Snippet – Async Lab - Ex03 - StartClick with CancellationToken - VB)

    Visual Basic

    Try
    Dim message = New HttpRequestMessage(HttpMethod.Get, "http://msdn.microsoft.com") Dim response = Await (New HttpClient()).SendAsync(message, cancellationToken.Token)FakePre-bdbdc6d239dd48c6ad0efc0fd9ecfc0e-d8b8993a00374129a16de7103596451bFakePre-17cc9753dadb4319a27452b4f9f43396-1ce32484781047bda678be2a15f4976dFakePre-de524866afa04c9e88559639b523d9bb-403dd43cfc6948be95be52558ae6bf2a

  7. In the DownloadItemAsync method, change the HttpClient.GetAsync call with an HttpClient.SendAsync call to include a cancellation token.

    (Code Snippet – Async Lab - Ex03 - DownloadItemAsync with CancellationToken - CS)

    C#

    try
    FakePre-d05abb2022a1486ca4c253e2c1ec648a-728e5b7324a9405a867ac4c518e4134dFakePre-6a181d7efe5d442c8a0ba278dfd59dc7-492af626080d4c0da4656365e8acfc01FakePre-7d2a8e78405146f69389a8feb60d9cd9-93087c985ca94ccc87cc7c6c831e24baFakePre-1ca1783e657e4aefa049637bfd647b1b-9adc129fc70b4b6d96c3685d61388db7 var message = new HttpRequestMessage(HttpMethod.Get, itemUri); var response = await httpClient.SendAsync(message, cancellationToken);FakePre-f9a0b949cc3d435ea9c63098ce72fcfa-9c9e9155919c43d899b7bb2b3d60aa59FakePre-45bfd77c6e3c443b9ff9ceb357000f91-cf3d3be8eb5b4cd1b139a87cab9bcc16

    (Code Snippet – Async Lab - Ex03 - DownloadItemAsync with CancellationToken - VB)

    Visual Basic

    Try
    FakePre-f417090f4d80420dbec93603746efb50-651d7f1d5c4f459abf816970dea359ddFakePre-b509eeabda3247c4ba7a93f182918b9f-871ecd4428c34c9fba1d5a9c2dba7f69FakePre-a3ced528db764f0488faf99eb4533301-abd0b858b0304425bee5acb046142cd1 Dim message = New HttpRequestMessage(HttpMethod.Get, itemUri) Dim response = Await httpClient.SendAsync(message, cancellationToken)FakePre-18271bfed0884bb4a69ab4ff24b635f9-856e8cda00254c02a0ef6091cedac071FakePre-6c40003487904aeb941cbac8a81906d1-47312532adc24f43ae6ee9fb60792109

  8. In the startButton_Click method, modify the DownloadItemAsync call in order to send the cancellation token. Replace the ListBox’s ItemsSource property assignment with the following code:

    (Code Snippet – Async Lab - Ex03 - Bind ListBox To Link Info - CS)

    C#

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

    (Code Snippet – Async Lab - Ex03 - Bind ListBox To Link Info - VB)

    Visual Basic

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

  9. In the startButton_Click try-catch block, add a new handler to catch the OperationCanceledException exception. Show a message box to tell the user that the operation was cancelled.

    (Code Snippet – Async Lab - Ex03 - OperationCanceledException Handler - CS)

    C#

    }
    catch (OperationCanceledException) { MessageBox.Show("Operation Cancelled"); }FakePre-da406334b90847c48f7ba0ced59596b3-a46f1b5f72c34cd4ad62466c56744499FakePre-6179ed0ce692493b8ba54ce8440d8a53-acdec413b4064394a2ee4ff7218d5014FakePre-92020d3ddbc3481d9666a8dd894758f8-61d6127ac68a49b494f03e1c792f9a83FakePre-00b2284292ee407aabc93e7169c65cec-cafd8b2447b245edbb6dc3bed0476e31

    (Code Snippet – Async Lab - Ex03 - OperationCanceledException Handler - VB)

    Visual Basic

    Catch exCancel As OperationCanceledException MessageBox.Show("Operation Cancelled")
    Catch ex As Exception
    FakePre-b7f743fe71c9415e986e62fbdd14328d-58a0cdb3965e4318af2bbb9b94131e53FakePre-bcbf09d3dd7144eb8091ce9da11bbdee-23dabefb5e8447d28a8defd432228213

  10. Open MainWindow.xaml Design View. Add a new button and set the name and the content to Cancel. If the buttons are not aligned, use the design view to place the buttons correctly in the grid. This is the XAML code of MainWindow.xaml you should obtain after the button is inserted:

    XAML

      <Grid>
    FakePre-bb074ca5b7714b8e8f9b5e5f12d27253-a0657b2b14114d5c9c07e26a0dcfca91FakePre-33c4fa694dff4edf9584f2a17ca3fcfd-838afe2b6697458bb6ed7e71123b7dc2FakePre-93f68f9ce6e24b7e8841f5ec32ac4baf-8ed26e4b23d74074a840796d953508c0FakePre-c3aba4f214fb4dc4b11373b0eaae1bd9-48d9728d685245c388480b05bc24bcaeFakePre-bd6e981cab29413584d3e27aee40e56e-af5d910173bf42608915e0b8c3b363b0 <Button Content="Cancel" Height="23" HorizontalAlignment="Left" Margin="318,406,0,0" Name="cancelButton" VerticalAlignment="Top" Width="75" />FakePre-bbd13b006b95451997918e2a46d8052a-e4222598d92e4b9887e33d8ee0f259f4FakePre-f81fd216b4664c83934632f5eecf89fb-737cee2a58064d87a9c3883102a4cca4

  11. Double-click the Cancel button to add an event handler.
  12. In the Cancel_Click event handler, call the Cancel method from the cancellation token.

    (Code Snippet – Async Lab - Ex03 - Cancel - CS)

    C#

    private void Cancel_Click(object sender, RoutedEventArgs e)
    FakePre-4651ce00c9d14ef8902e267d7ebd35c5-152f0a7454d645fa9e72e0643a2abbd9 cancellationToken.Cancel();FakePre-a32d4cbe27184391b2553bc8f0197893-6bbafb1fa8ad43f5b16a05e1f26edb1f

    (Code Snippet – Async Lab - Ex03 - Cancel - VB)

    Visual Basic

    Private Sub Cancel_Click(sender As Object, 
    FakePre-f4593990cf7d43b4bfc7b030543ab5ec-d3e5273822274047837ffdc1d6dbf6ffFakePre-fce2423dfd42440ab901089f3856b863-fc1f83d6b19b449a926d2bc71a832296 cancellationToken.Cancel()FakePre-8d85cc6ac21a4797bcd31df33e6aacce-2192f926230b473783f075e0838e39b5

  13. Press F5 to run the application, and then, click the Start button.
  14. Press the Cancel button. Notice you can now cancel the operation before it completes. The list on the right will only show the links that were requested before the cancellation occurred.

    Figure 3

    Application updated with Cancel button

In this task, you will add the ability to poll the links status and use different colors when their content has changed.

  1. Replace all the code of LinkInfo class with the following code. You will implement INotifyPropertyChanged, taking advantage of the real time binding. Additionally, you will be adding a new property named Color. Notice that the set was implemented in all the properties to notify the changes.

    (Code Snippet – Async Lab - Ex03 - LinkInfo - CS)

    C#

    namespace AsyncLab { using System.ComponentModel; using System.Windows.Media; public class LinkInfo : INotifyPropertyChanged { private string html; private string title; private int length; private Color color; public event PropertyChangedEventHandler PropertyChanged; public string Title { get { return title; } set { title = value; NotifyPropertyChanged("Title"); } } public string Html { get { return html; } set { html = value; NotifyPropertyChanged("Html"); } } public int Length { get { return length; } set { length = value; NotifyPropertyChanged("Length"); } } public Color Color { get { return color; } set { color = value; NotifyPropertyChanged("Color"); } } private void NotifyPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } }
    
    FakePre-a29870789639478cbb371658c19e4bbe-2ff5cd71eb604c06a7c1c6037fbd3613FakePre-dffe8d47339d4e5e8b4caeea9b18eea2-9222fb3e09c34525bf48133e9a5a6f35FakePre-e50e20af859243e880fc056373498b22-17d432a9593c4977b00208bbec05bb77FakePre-3dbb95cf322c4e4fbc1cb5141f87696f-3a39571c2356485d8a1af05dc5d6d523FakePre-1940659354ea45c38a72ca6a89b017ae-670ded56bf54462ab0bd4e58c751f01aFakePre-fa42c771cbbb451a98a56d017af63a21-4c91e01385d94bc6b52482bdeec0e647FakePre-03dbb52b860f46c08e0f855f7597cd5f-175d0c7c297a47c198986fb59267ae49FakePre-ef8f90289aa4419caac3f286846fd2c0-363efc7e8cb24c1e905919e17f6a706d
    

    (Code Snippet – Async Lab - Ex03 - LinkInfo - VB)

    Visual Basic

    Imports System.ComponentModel Imports System.Windows.Media Public Class LinkInfo Implements INotifyPropertyChanged Private mHtml As String Private mTitle As String Private mLength As Integer Private mColor As Color Public Event PropertyChanged(sender As Object, e As PropertyChangedEventArgs) _ Implements INotifyPropertyChanged.PropertyChanged Public Property Html() As String Get Return mHtml End Get Set(ByVal value As String) mHtml = value NotifyPropertyChanged("Html") End Set End Property Public Property Title() As String Get Return mTitle End Get Set(ByVal value As String) mTitle = value NotifyPropertyChanged("Title") End Set End Property Public Property Length() As Integer Get Return mLength End Get Set(ByVal value As Integer) mLength = value NotifyPropertyChanged("Length") End Set End Property Public Property Color() As Color Get Return mColor End Get Set(ByVal value As Color) mColor = value NotifyPropertyChanged("Color") End Set End Property Private Sub NotifyPropertyChanged(propertyName As String) RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName)) End Sub End Class
    
    FakePre-7d06394a6eb341f2bbbe5f110b4ffe5a-6d73a12a179d4fc4ae3701c5053b3e12FakePre-515f66a64a6549249c07c44095824361-3e2a934b0f8c4665b8ad6b2a044c253aFakePre-7afa6ff95dbc4764813b68e6619b572f-b5571a72f934468dbb3db450922bba0bFakePre-ac122ee584bc45ee82aed4b7be608c6b-abdc3b4c2d8745d99f941232627cd18cFakePre-5b707da841e64175aa9ce00d2f8ebba9-3c3637376aa0490d8b3e9fbb01a73909FakePre-d6a652468d724498a8495afdbecf52a6-d89241ffd5ef41bda1d0397bfb8f0e95FakePre-4bfda61e86dd4e5b94a09cb4ff7271f0-82833d52ccad424dbf6d74cc1089eabe
    

  2. In the MainWindow.xaml file, modify the DataTemplate resource to include a SolidColorBrush in the TextBlock.Background and bound the Color attribute to the Color property.

    XAML

    <Window.Resources>
    FakePre-8b4049864c424442959cfd31ab47a25e-61edbcc18eec4d749c0268a7a28f682cFakePre-126c3ba089714b9a8dc46fe05c5d5a46-a860a55bb15343a2a2926e95ed336e45FakePre-6361877fd0204c3a9d06d14d5379f020-29ad4120fa684e79843d71f223778c80 <TextBlock.Background> <SolidColorBrush Color="{Binding Color}" /> </TextBlock.Background>FakePre-b8eb7e5cb12f4fb5aee1bc02aef1bb32-58d736cb8d77449ca6ca96fd72e012b6

  3. Open the MainWindow.xaml.cs or MainWindows.xaml.vb file and add the PollItem async method. It will receive an URI, a LinkInfo and a CancellationToken.

    (Code Snippet – Async Lab - Ex03 - PollInfo Method - CS)

    C#

    private static async void PollItem( Uri itemUri, LinkInfo link, CancellationToken cancellationToken) { }
    
    

    (Code Snippet – Async Lab - Ex03 - PollInfo Method - VB)

    Visual Basic

    Private Shared Async Sub PollItem(ByVal itemUri As Uri, ByVal link As LinkInfo, ByVal cancellationToken As CancellationToken) End Sub
    
    

  4. Implement the PollItem method to poll the URI every 5 seconds and check for changes in the content. Each time a change is found, it updates the LinkInfo by changing the color property with a random color.

    (Code Snippet – Async Lab - Ex03 - PollInfo Implementation - CS)

    C#

    private static async void PollItem(Uri itemUri, LinkInfo link, 
    FakePre-a5fe77d13d824e398cee0b8a7921d796-63fc669494004027b480c71a59b57d39FakePre-68663456677a46c2a7514f295c9215d1-97af77ccc7104c239580a8fcbeb066ad Random r = new Random(); HttpClient httpClient = new HttpClient(); httpClient.MaxResponseContentBufferSize = 1000000; try { while (true) { await Task.Delay(5000, cancellationToken); var requestMessage = new HttpRequestMessage( HttpMethod.Get, itemUri); var response = await httpClient.SendAsync(requestMessage, cancellationToken); string item = await response.Content.ReadAsStringAsync(); if (item.Length != link.Length) { link.Title = GetTitle(item); link.Length = item.Length; link.Html = item; link.Color = Color.FromArgb((byte)255, (byte)r.Next(256), (byte)r.Next(256), (byte)r.Next(256)); } } } catch { }FakePre-2cf3570b8ef847d1b619f0c4683e7cb9-00b81635f0664242a553db3cfc28b510FakePre-aa6a8b86a9d444ce9b62f538ee659e96-2ed4b06eb99d4b40ad498a171579ce20FakePre-d0ee8847850540d5b1d13c5cdcd3a0c4-4da0bee94d864e2ca9b19ef22e367922

    (Code Snippet – Async Lab - Ex03 - PollInfo Implementation - VB)

    Visual Basic

    Private Shared Async Sub PollItem(ByVal itemUri As Uri, 
    FakePre-1603026e8ded4a7084585bc5a52faee7-160252a01ab84cc19439f0a4b5e89ec5FakePre-2342cf2c95bc493c8c4890765a8b5261-59f91ad848704c68b889191504af3cad Dim r As New Random() Dim httpClient As New HttpClient httpClient.MaxResponseContentBufferSize = 1000000 Try Do Await Task.Delay(5000, cancellationToken) Dim requestMessage = New HttpRequestMessage( HttpMethod.Get, itemUri) Dim response = Await httpClient.SendAsync(requestMessage, cancellationToken) Dim item As String = Await response.Content.ReadAsStringAsync() If item.Length <> link.Length Then link.Title = GetTitle(item) link.Length = item.Length link.Html = item link.Color = Color.FromArgb(Convert.ToByte(255), Convert.ToByte(r.Next(256)), Convert.ToByte(r.Next(256)), Convert.ToByte(r.Next(256))) End If Loop Catch End TryFakePre-7a3896728b114aa6b04add27ef2efdf7-6a0ca6bb512647fabfccfe77d527ca21FakePre-3eaa709d8ec24eb5811eddad6326da09-1e895524402d4e8d8f14413036228e08

    Note:
    Task.Delay is the asynchronous version of Thread.Sleep. It returns a Task object, which completes after the specified amount of time.

  5. In the DownloadItemAsync function, add a call to PollItem.

    (Code Snippet – Async Lab - Ex03 - PollInfo Call - CS)

    C#

    public static async Task<LinkInfo> DownloadItemAsync(Uri itemUri, 
    FakePre-a20983ee797f4240890729ba3e28184b-62f15350b4f846e9a291cd2a36e44c1aFakePre-335766c5c7594579b6c7cc020a11063d-8b4245689a8a4b42a6c59c4f1faa76f8FakePre-e41a5d74093449b4a0f7b794b31cb45b-1347c9ff9c5f432b86b738ffdb6e5ac4FakePre-d6781c6406614436a2610416e225a074-681b666b1b3240759dd5c871ecd19526FakePre-3104a610c41a4f9aa8b204df7345f01f-30792bf801a942a9a64c1e6b1b4c6f89FakePre-d7830a7d982f486385cad440ab6f7bdd-89863ed86df643bea830fe457aab9776FakePre-0b3b8d1741134dc3b03843b0c315cdf2-0b50ba1ecec14116952859d0e701d7a7 PollItem(itemUri, linkInfo, cancellationToken);FakePre-1e35ca3afe354782b1b10c3f2ea2cc77-c14a2005f9604a70b37783fc68abb126FakePre-a6377c4fc27d494592fc746a77d1e1b8-e264376002ef4273a70bd4c83f3c807eFakePre-4c5333a476ae4b18b4988b74663b2977-aa46f856c93b440b83ad1902d3dfdf79

    (Code Snippet – Async Lab - Ex03 - PollInfo Call - VB)

    Visual Basic

    Private Shared Async Function DownloadItemAsync(ByVal itemUri As Uri, 
    FakePre-af6fb6c0660e47f8943b06a431bd9cad-b96b9d1308bb430fbbf36647772c3c2eFakePre-8abd1ab7f1324cdeb749c02abac0479c-69642b2f444048f4abf0bf9d909ed73aFakePre-728ddc7b79d24595a4cd746e7c2ebfee-9e2b5093f953401bb936fe0d65c80ae9FakePre-a7d6e85cc9894157a4d3e268f38cdf82-a1772c5c718a4237b5df79e41811119eFakePre-f77366b8afae4f27a63af03278c0c078-2831ecaa97e7496aa4e1b743bb5baefbFakePre-a3686891e9044110b082b980fa749427-9ebec57169b9481181811b30a1a14970 PollItem(itemUri, linkInfo, cancellationToken)FakePre-ed4e4f935d124b4dbed3b5450a9bb63a-a998bf9805a24d5fafdf054682fbccd8FakePre-7d780a546c9943b890eafac26e533625-fc03ff7b963c4ff3bae0bb020b30a1beFakePre-0ae6d27f08624b8fab07ee27cb6d57fc-27def95ddfac4049a4c0bb7c64494dac

  6. Press F5 to run the application, and then click the Start button. Notice the background color of the list items change when the application detects an update.

    Figure 4

    Polling links status