Cancel an Async Task or a List of Tasks (C# and Visual Basic)
You can set up a button that you can use to cancel an async application if you don't want to wait for it to finish. By following the examples in this topic, you can add a cancellation button to an application that downloads the contents of one website or a list of websites.
The examples use the UI that Fine-Tuning Your Async Application (C# and Visual Basic) describes.
Note
To run the examples, you must have Visual Studio 2012, Visual Studio 2013, Visual Studio Express 2012 for Windows Desktop, Visual Studio Express 2013 for Windows, or the .NET Framework 4.5 or 4.5.1 installed on your computer.
Cancel a Task
The first example associates the Cancel button with a single download task. If you choose the button while the application is downloading content, the download is canceled.
Downloading the Example
You can download the complete Windows Presentation Foundation (WPF) project from Async Sample: Fine Tuning Your Application and then follow these steps.
Decompress the file that you downloaded, and then start Visual Studio.
On the menu bar, choose File, Open, Project/Solution.
In the Open Project dialog box, open the folder that holds the sample code that you decompressed, and then open the solution (.sln) file for AsyncFineTuningCS or AsyncFineTuningVB.
In Solution Explorer, open the shortcut menu for the CancelATask project, and then choose Set as StartUp Project.
Choose the F5 key to run the project.
Choose the Ctrl+F5 keys to run the project without debugging it.
If you don't want to download the project, you can review the MainWindow.xaml.vb and MainWindow.xaml.cs files at the end of this topic.
Building the Example
The following changes add a Cancel button to an application that downloads a website. If you don't want to download or build the example, you can review the final product in the "Complete Examples" section at the end of this topic. Asterisks mark the changes in the code.
To build the example yourself, step by step, follow the instructions in the "Downloading the Example" section, but choose StarterCode as the StartUp Project instead of CancelATask.
Then add the following changes to the MainWindow.xaml.vb or MainWindow.xaml.cs file of that project.
Declare a CancellationTokenSource variable, cts, that’s in scope for all methods that access it.
Class MainWindow ' ***Declare a System.Threading.CancellationTokenSource. Dim cts As CancellationTokenSource
public partial class MainWindow : Window { // ***Declare a System.Threading.CancellationTokenSource. CancellationTokenSource cts;
Add the following event handler for the Cancel button. The event handler uses the CancellationTokenSource.Cancel method to notify cts when the user requests cancellation.
' ***Add an event handler for the Cancel button. Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs) If cts IsNot Nothing Then cts.Cancel() End If End Sub
// ***Add an event handler for the Cancel button. private void cancelButton_Click(object sender, RoutedEventArgs e) { if (cts != null) { cts.Cancel(); } }
Make the following changes in the event handler for the Start button, startButton_Click.
Instantiate the CancellationTokenSource, cts.
' ***Instantiate the CancellationTokenSource. cts = New CancellationTokenSource()
// ***Instantiate the CancellationTokenSource. cts = new CancellationTokenSource();
In the call to AccessTheWebAsync, which downloads the contents of a specified website, send the CancellationTokenSource.Token property of cts as an argument. The Token property propagates the message if cancellation is requested. Add a catch block that displays a message if the user chooses to cancel the download operation. The following code shows the changes.
Try ' ***Send a token to carry the message if cancellation is requested. Dim contentLength As Integer = Await AccessTheWebAsync(cts.Token) resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength) ' *** If cancellation is requested, an OperationCanceledException results. Catch ex As OperationCanceledException resultsTextBox.Text &= vbCrLf & "Download canceled." & vbCrLf Catch ex As Exception resultsTextBox.Text &= vbCrLf & "Download failed." & vbCrLf End Try
try { // ***Send a token to carry the message if cancellation is requested. int contentLength = await AccessTheWebAsync(cts.Token); resultsTextBox.Text += String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength); } // *** If cancellation is requested, an OperationCanceledException results. catch (OperationCanceledException) { resultsTextBox.Text += "\r\nDownload canceled.\r\n"; } catch (Exception) { resultsTextBox.Text += "\r\nDownload failed.\r\n"; }
In AccessTheWebAsync, use the HttpClient.GetAsync(String, CancellationToken) overload of the GetAsync method in the HttpClient type to download the contents of a website. Pass ct, the CancellationToken parameter of AccessTheWebAsync, as the second argument. The token carries the message if the user chooses the Cancel button.
The following code shows the changes in AccessTheWebAsync.
' ***Provide a parameter for the CancellationToken. Async Function AccessTheWebAsync(ct As CancellationToken) As Task(Of Integer) Dim client As HttpClient = New HttpClient() resultsTextBox.Text &= String.Format(vbCrLf & "Ready to download." & vbCrLf) ' You might need to slow things down to have a chance to cancel. Await Task.Delay(250) ' GetAsync returns a Task(Of HttpResponseMessage). ' ***The ct argument carries the message if the Cancel button is chosen. Dim response As HttpResponseMessage = Await client.GetAsync("https://msdn.microsoft.com/en-us/library/dd470362.aspx", ct) ' Retrieve the website contents from the HttpResponseMessage. Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync() ' The result of the method is the length of the downloaded website. Return urlContents.Length End Function
// ***Provide a parameter for the CancellationToken. async Task<int> AccessTheWebAsync(CancellationToken ct) { HttpClient client = new HttpClient(); resultsTextBox.Text += String.Format("\r\nReady to download.\r\n"); // You might need to slow things down to have a chance to cancel. await Task.Delay(250); // GetAsync returns a Task<HttpResponseMessage>. // ***The ct argument carries the message if the Cancel button is chosen. HttpResponseMessage response = await client.GetAsync("https://msdn.microsoft.com/en-us/library/dd470362.aspx", ct); // Retrieve the website contents from the HttpResponseMessage. byte[] urlContents = await response.Content.ReadAsByteArrayAsync(); // The result of the method is the length of the downloaded website. return urlContents.Length; }
If you don’t cancel the program, it produces the following output.
Ready to download. Length of the downloaded string: 158125.
If you choose the Cancel button before the program finishes downloading the content, the program produces the following output.
Ready to download. Download canceled.
Cancel a List of Tasks
You can extend the previous example to cancel many tasks by associating the same CancellationTokenSource instance with each task. If you choose the Cancel button, you cancel all tasks that aren’t yet complete.
Downloading the Example
You can download the complete Windows Presentation Foundation (WPF) project from Async Sample: Fine Tuning Your Application and then follow these steps.
Decompress the file that you downloaded, and then start Visual Studio 2012.
On the menu bar, choose File, Open, Project/Solution.
In the Open Project dialog box, open the folder that holds the sample code that you decompressed, and then open the solution (.sln) file for AsyncFineTuningCS or AsyncFineTuningVB.
In Solution Explorer, open the shortcut menu for the CancelAListOfTasks project, and then choose Set as StartUp Project.
Choose the F5 key to run the project.
Choose the Ctrl+F5 keys to run the project without debugging it.
If you don't want to download the project, you can review the MainWindow.xaml.vb and MainWindow.xaml.cs files at the end of this topic.
Building the Example
To extend the example yourself, step by step, follow the instructions in the "Downloading the Example" section, but choose CancelATask as the StartUp Project. Add the following changes to that project. Asterisks mark the changes in the program.
Add a method to create a list of web addresses.
' ***Add a method that creates a list of web addresses. Private Function SetUpURLList() As List(Of String) Dim urls = New List(Of String) From { "https://msdn.microsoft.com", "https://msdn.microsoft.com/en-us/library/hh290138.aspx", "https://msdn.microsoft.com/en-us/library/hh290140.aspx", "https://msdn.microsoft.com/en-us/library/dd470362.aspx", "https://msdn.microsoft.com/en-us/library/aa578028.aspx", "https://msdn.microsoft.com/en-us/library/ms404677.aspx", "https://msdn.microsoft.com/en-us/library/ff730837.aspx" } Return urls End Function
// ***Add a method that creates a list of web addresses. private List<string> SetUpURLList() { List<string> urls = new List<string> { "https://msdn.microsoft.com", "https://msdn.microsoft.com/en-us/library/hh290138.aspx", "https://msdn.microsoft.com/en-us/library/hh290140.aspx", "https://msdn.microsoft.com/en-us/library/dd470362.aspx", "https://msdn.microsoft.com/en-us/library/aa578028.aspx", "https://msdn.microsoft.com/en-us/library/ms404677.aspx", "https://msdn.microsoft.com/en-us/library/ff730837.aspx" }; return urls; }
Call the method in AccessTheWebAsync.
' ***Call SetUpURLList to make a list of web addresses. Dim urlList As List(Of String) = SetUpURLList()
// ***Call SetUpURLList to make a list of web addresses. List<string> urlList = SetUpURLList();
Add the following loop in AccessTheWebAsync to process each web address in the list.
' ***Add a loop to process the list of web addresses. For Each url In urlList ' GetAsync returns a Task(Of HttpResponseMessage). ' Argument ct carries the message if the Cancel button is chosen. ' ***Note that the Cancel button can cancel all remaining downloads. Dim response As HttpResponseMessage = Await client.GetAsync(url, ct) ' Retrieve the website contents from the HttpResponseMessage. Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync() resultsTextBox.Text &= String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, urlContents.Length) Next
// ***Add a loop to process the list of web addresses. foreach (var url in urlList) { // GetAsync returns a Task<HttpResponseMessage>. // Argument ct carries the message if the Cancel button is chosen. // ***Note that the Cancel button can cancel all remaining downloads. HttpResponseMessage response = await client.GetAsync(url, ct); // Retrieve the website contents from the HttpResponseMessage. byte[] urlContents = await response.Content.ReadAsByteArrayAsync(); resultsTextBox.Text += String.Format("\r\nLength of the downloaded string: {0}.\r\n", urlContents.Length); }
Because AccessTheWebAsync displays the lengths, the method doesn't need to return anything. Remove the return statement, and change the return type of the method to Task instead of Task<TResult>.
Async Function AccessTheWebAsync(ct As CancellationToken) As Task
async Task AccessTheWebAsync(CancellationToken ct)
Call the method from startButton_Click by using a statement instead of an expression.
Await AccessTheWebAsync(cts.Token)
await AccessTheWebAsync(cts.Token);
If you don’t cancel the program, it produces the following output.
Length of the downloaded string: 35939. Length of the downloaded string: 237682. Length of the downloaded string: 128607. Length of the downloaded string: 158124. Length of the downloaded string: 204890. Length of the downloaded string: 175488. Length of the downloaded string: 145790. Downloads complete.
If you choose the Cancel button before the downloads are complete, the output contains the lengths of the downloads that completed before the cancellation.
Length of the downloaded string: 35939. Length of the downloaded string: 237682. Length of the downloaded string: 128607. Downloads canceled.
Complete Examples
The following sections contain the code for each of the previous examples. Notice that you must add a reference for System.Net.Http.
You can download the projects from Async Sample: Fine Tuning Your Application.
Cancel a Task Example
The following code is the complete MainWindow.xaml.vb or MainWindow.xaml.cs file for the example that cancels a single task.
' Add an Imports directive and a reference for System.Net.Http.
Imports System.Net.Http
' Add the following Imports directive for System.Threading.
Imports System.Threading
Class MainWindow
' ***Declare a System.Threading.CancellationTokenSource.
Dim cts As CancellationTokenSource
Private Async Sub startButton_Click(sender As Object, e As RoutedEventArgs)
' ***Instantiate the CancellationTokenSource.
cts = New CancellationTokenSource()
resultsTextBox.Clear()
Try
' ***Send a token to carry the message if cancellation is requested.
Dim contentLength As Integer = Await AccessTheWebAsync(cts.Token)
resultsTextBox.Text &=
String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, contentLength)
' *** If cancellation is requested, an OperationCanceledException results.
Catch ex As OperationCanceledException
resultsTextBox.Text &= vbCrLf & "Download canceled." & vbCrLf
Catch ex As Exception
resultsTextBox.Text &= vbCrLf & "Download failed." & vbCrLf
End Try
' ***Set the CancellationTokenSource to Nothing when the download is complete.
cts = Nothing
End Sub
' ***Add an event handler for the Cancel button.
Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs)
If cts IsNot Nothing Then
cts.Cancel()
End If
End Sub
' ***Provide a parameter for the CancellationToken.
Async Function AccessTheWebAsync(ct As CancellationToken) As Task(Of Integer)
Dim client As HttpClient = New HttpClient()
resultsTextBox.Text &=
String.Format(vbCrLf & "Ready to download." & vbCrLf)
' You might need to slow things down to have a chance to cancel.
Await Task.Delay(250)
' GetAsync returns a Task(Of HttpResponseMessage).
' ***The ct argument carries the message if the Cancel button is chosen.
Dim response As HttpResponseMessage = Await client.GetAsync("https://msdn.microsoft.com/en-us/library/dd470362.aspx", ct)
' Retrieve the website contents from the HttpResponseMessage.
Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()
' The result of the method is the length of the downloaded website.
Return urlContents.Length
End Function
End Class
' Output for a successful download:
' Ready to download.
' Length of the downloaded string: 158125.
' Or, if you cancel:
' Ready to download.
' Download canceled.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
// Add a using directive and a reference for System.Net.Http.
using System.Net.Http;
// Add the following using directive for System.Threading.
using System.Threading;
namespace CancelATask
{
public partial class MainWindow : Window
{
// ***Declare a System.Threading.CancellationTokenSource.
CancellationTokenSource cts;
public MainWindow()
{
InitializeComponent();
}
private async void startButton_Click(object sender, RoutedEventArgs e)
{
// ***Instantiate the CancellationTokenSource.
cts = new CancellationTokenSource();
resultsTextBox.Clear();
try
{
// ***Send a token to carry the message if cancellation is requested.
int contentLength = await AccessTheWebAsync(cts.Token);
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", contentLength);
}
// *** If cancellation is requested, an OperationCanceledException results.
catch (OperationCanceledException)
{
resultsTextBox.Text += "\r\nDownload canceled.\r\n";
}
catch (Exception)
{
resultsTextBox.Text += "\r\nDownload failed.\r\n";
}
// ***Set the CancellationTokenSource to null when the download is complete.
cts = null;
}
// ***Add an event handler for the Cancel button.
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}
// ***Provide a parameter for the CancellationToken.
async Task<int> AccessTheWebAsync(CancellationToken ct)
{
HttpClient client = new HttpClient();
resultsTextBox.Text +=
String.Format("\r\nReady to download.\r\n");
// You might need to slow things down to have a chance to cancel.
await Task.Delay(250);
// GetAsync returns a Task<HttpResponseMessage>.
// ***The ct argument carries the message if the Cancel button is chosen.
HttpResponseMessage response = await client.GetAsync("https://msdn.microsoft.com/en-us/library/dd470362.aspx", ct);
// Retrieve the website contents from the HttpResponseMessage.
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
// The result of the method is the length of the downloaded website.
return urlContents.Length;
}
}
// Output for a successful download:
// Ready to download.
// Length of the downloaded string: 158125.
// Or, if you cancel:
// Ready to download.
// Download canceled.
}
Cancel a List of Tasks Example
The following code is the complete MainWindow.xaml.vb or MainWindow.xaml.cs file for the example that cancels a list of tasks.
' Add an Imports directive and a reference for System.Net.Http.
Imports System.Net.Http
' Add the following Imports directive for System.Threading.
Imports System.Threading
Class MainWindow
' Declare a System.Threading.CancellationTokenSource.
Dim cts As CancellationTokenSource
Private Async Sub startButton_Click(sender As Object, e As RoutedEventArgs)
' Instantiate the CancellationTokenSource.
cts = New CancellationTokenSource()
resultsTextBox.Clear()
Try
' ***AccessTheWebAsync returns a Task, not a Task(Of Integer).
Await AccessTheWebAsync(cts.Token)
' ***Small change in the display lines.
resultsTextBox.Text &= vbCrLf & "Downloads complete."
Catch ex As OperationCanceledException
resultsTextBox.Text &= vbCrLf & "Downloads canceled." & vbCrLf
Catch ex As Exception
resultsTextBox.Text &= vbCrLf & "Downloads failed." & vbCrLf
End Try
' Set the CancellationTokenSource to Nothing when the download is complete.
cts = Nothing
End Sub
' Add an event handler for the Cancel button.
Private Sub cancelButton_Click(sender As Object, e As RoutedEventArgs)
If cts IsNot Nothing Then
cts.Cancel()
End If
End Sub
' Provide a parameter for the CancellationToken.
' ***Change the return type to Task because the method has no return statement.
Async Function AccessTheWebAsync(ct As CancellationToken) As Task
Dim client As HttpClient = New HttpClient()
' ***Call SetUpURLList to make a list of web addresses.
Dim urlList As List(Of String) = SetUpURLList()
' ***Add a loop to process the list of web addresses.
For Each url In urlList
' GetAsync returns a Task(Of HttpResponseMessage).
' Argument ct carries the message if the Cancel button is chosen.
' ***Note that the Cancel button can cancel all remaining downloads.
Dim response As HttpResponseMessage = Await client.GetAsync(url, ct)
' Retrieve the website contents from the HttpResponseMessage.
Dim urlContents As Byte() = Await response.Content.ReadAsByteArrayAsync()
resultsTextBox.Text &=
String.Format(vbCrLf & "Length of the downloaded string: {0}." & vbCrLf, urlContents.Length)
Next
End Function
' ***Add a method that creates a list of web addresses.
Private Function SetUpURLList() As List(Of String)
Dim urls = New List(Of String) From
{
"https://msdn.microsoft.com",
"https://msdn.microsoft.com/en-us/library/hh290138.aspx",
"https://msdn.microsoft.com/en-us/library/hh290140.aspx",
"https://msdn.microsoft.com/en-us/library/dd470362.aspx",
"https://msdn.microsoft.com/en-us/library/aa578028.aspx",
"https://msdn.microsoft.com/en-us/library/ms404677.aspx",
"https://msdn.microsoft.com/en-us/library/ff730837.aspx"
}
Return urls
End Function
End Class
' Output if you do not choose to cancel:
' Length of the downloaded string: 35939.
' Length of the downloaded string: 237682.
' Length of the downloaded string: 128607.
' Length of the downloaded string: 158124.
' Length of the downloaded string: 204890.
' Length of the downloaded string: 175488.
' Length of the downloaded string: 145790.
' Downloads complete.
' Sample output if you choose to cancel:
' Length of the downloaded string: 35939.
' Length of the downloaded string: 237682.
' Length of the downloaded string: 128607.
' Downloads canceled.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
// Add a using directive and a reference for System.Net.Http.
using System.Net.Http;
// Add the following using directive for System.Threading.
using System.Threading;
namespace CancelAListOfTasks
{
public partial class MainWindow : Window
{
// Declare a System.Threading.CancellationTokenSource.
CancellationTokenSource cts;
public MainWindow()
{
InitializeComponent();
}
private async void startButton_Click(object sender, RoutedEventArgs e)
{
// Instantiate the CancellationTokenSource.
cts = new CancellationTokenSource();
resultsTextBox.Clear();
try
{
await AccessTheWebAsync(cts.Token);
// ***Small change in the display lines.
resultsTextBox.Text += "\r\nDownloads complete.";
}
catch (OperationCanceledException)
{
resultsTextBox.Text += "\r\nDownloads canceled.";
}
catch (Exception)
{
resultsTextBox.Text += "\r\nDownloads failed.";
}
// Set the CancellationTokenSource to null when the download is complete.
cts = null;
}
// Add an event handler for the Cancel button.
private void cancelButton_Click(object sender, RoutedEventArgs e)
{
if (cts != null)
{
cts.Cancel();
}
}
// Provide a parameter for the CancellationToken.
// ***Change the return type to Task because the method has no return statement.
async Task AccessTheWebAsync(CancellationToken ct)
{
// Declare an HttpClient object.
HttpClient client = new HttpClient();
// ***Call SetUpURLList to make a list of web addresses.
List<string> urlList = SetUpURLList();
// ***Add a loop to process the list of web addresses.
foreach (var url in urlList)
{
// GetAsync returns a Task<HttpResponseMessage>.
// Argument ct carries the message if the Cancel button is chosen.
// ***Note that the Cancel button can cancel all remaining downloads.
HttpResponseMessage response = await client.GetAsync(url, ct);
// Retrieve the website contents from the HttpResponseMessage.
byte[] urlContents = await response.Content.ReadAsByteArrayAsync();
resultsTextBox.Text +=
String.Format("\r\nLength of the downloaded string: {0}.\r\n", urlContents.Length);
}
}
// ***Add a method that creates a list of web addresses.
private List<string> SetUpURLList()
{
List<string> urls = new List<string>
{
"https://msdn.microsoft.com",
"https://msdn.microsoft.com/en-us/library/hh290138.aspx",
"https://msdn.microsoft.com/en-us/library/hh290140.aspx",
"https://msdn.microsoft.com/en-us/library/dd470362.aspx",
"https://msdn.microsoft.com/en-us/library/aa578028.aspx",
"https://msdn.microsoft.com/en-us/library/ms404677.aspx",
"https://msdn.microsoft.com/en-us/library/ff730837.aspx"
};
return urls;
}
}
// Output if you do not choose to cancel:
//Length of the downloaded string: 35939.
//Length of the downloaded string: 237682.
//Length of the downloaded string: 128607.
//Length of the downloaded string: 158124.
//Length of the downloaded string: 204890.
//Length of the downloaded string: 175488.
//Length of the downloaded string: 145790.
//Downloads complete.
// Sample output if you choose to cancel:
//Length of the downloaded string: 35939.
//Length of the downloaded string: 237682.
//Length of the downloaded string: 128607.
//Downloads canceled.
}
See Also
Reference
Concepts
Asynchronous Programming with Async and Await (C# and Visual Basic)
Fine-Tuning Your Async Application (C# and Visual Basic)