How to: Register Callbacks for Cancellation Requests
The following example shows how to register a delegate that will be invoked when a IsCancellationRequested property becomes true due to a call to Cancel on the object that created the token. Use this technique for cancelling asynchronous operations that do not natively support the unified cancellation framework, and for unblocking methods that might be waiting for an asynchronous operation to finish.
Note
When "Just My Code" is enabled, Visual Studio in some cases will break on the line that throws the exception and display an error message that says "exception not handled by user code." This error is benign. You can press F5 to continue from it, and see the exception-handling behavior that is demonstrated in the examples below. To prevent Visual Studio from breaking on the first error, just uncheck the "Just My Code" checkbox under Tools, Options, Debugging, General.
Example
In the following example, the CancelAsync method is registered as the method to be invoked when cancellation is requested through the cancellation token.
Class CancelWithCallback
Shared Sub Main()
Dim cts As New CancellationTokenSource()
' Start cancelable task.
Dim t As Task = Task.Factory.StartNew(Sub() DoWork(cts.Token))
Console.WriteLine("Press 'c' to cancel.")
Dim ch As Char = Console.ReadKey().KeyChar
If ch = "c"c Then
cts.Cancel()
End If
Console.WriteLine("Press any key to exit.")
Console.ReadKey()
End Sub
Shared Sub DoWork(ByVal token As CancellationToken)
Dim wc As New WebClient()
' Create an event handler to receive the result.
AddHandler wc.DownloadStringCompleted, Sub(obj, e)
' Checks status of WebClient, not external token
If e.Cancelled = False Then
Console.WriteLine(e.Result + "\r\nPress any key.")
Else
Console.WriteLine("Download was canceled.")
End If
End Sub
token.Register(Sub() wc.CancelAsync())
Console.WriteLine("Starting request")
wc.DownloadStringAsync(New Uri("https://www.contoso.com"))
End Sub
End Class
namespace Cancel3
{
using System;
using System.Net;
using System.Threading;
using System.Threading.Tasks;
class CancelWithCallback
{
static void Main(string[] args)
{
var cts = new CancellationTokenSource();
// Start cancelable task.
Task t = Task.Factory.StartNew(() =>
{
DoWork(cts.Token);
});
Console.WriteLine("Press 'c' to cancel.");
char ch = Console.ReadKey().KeyChar;
if (ch == 'c')
{
cts.Cancel();
}
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
static void DoWork(CancellationToken token)
{
WebClient wc = new WebClient();
// Create an event handler to receive the result.
wc.DownloadStringCompleted += (obj, e) =>
{
// Checks status of WebClient, not external token
if (!e.Cancelled)
{
Console.WriteLine(e.Result + "\r\nPress any key.");
}
else
Console.WriteLine("Download was canceled.");
};
// Do not initiate download if the external token
// has already been canceled.
if (!token.IsCancellationRequested)
{
// Register the callback to a method that can unblock.
// Dispose of the CancellationTokenRegistration object
// after the callback has completed.
using (CancellationTokenRegistration ctr = token.Register(() => wc.CancelAsync()))
{
Console.WriteLine("Starting request");
wc.DownloadStringAsync(new Uri("https://www.contoso.com"));
}
}
}
}
}
If cancellation has already been requested when the callback is registered, the callback is still guaranteed to be called. In this particular case, the CancelAsync method will do nothing if no asynchronous operation is in progress, so it is always safe to call the method.