How to use cancellation tokens in ASP.NET Core 7
Although ASP.NET Core 7 is the latest version of Microsoft’s open-source web application development framework, it leverages many important features from previous versions of .NET. One such important feature is cancellation tokens, which provide a way to easily handle multithreaded applications.
When working with ASP.NET Core applications, it’s a good practice to kill long-running operations (e.g. a database query or a background process) either after a period of time or at user request so that the application can free up resources and remain responsive. This is where cancellation tokens come into play.
This article explains cancellation tokens, why they’re useful, and how to use them in minimal API handlers in ASP.NET Core. In order to work with the code samples provided in this article, Visual Studio 2022 Preview should be installed on your system. If you don’t already have a copy, you can download Visual Studio 2022 here.
Create a minimal ASP.NET Core 7 Web API project in Visual Studio 2022
First, let’s create a minimal ASP.NET Core API project in Visual Studio. The following steps create a new ASP.NET Core 7 Web API project in Visual Studio 2022 Preview:
- Launch the Visual Studio 2022 Preview IDE.
- Click on “Create new project”.
- In the Create a new project window, select “ASP.NET Core Web API” from the list of templates that appear.
- Click next.
- In the Configure New Project window, specify the name and location for the new project.
- Optionally check the “Place solution and project in the same directory” checkbox based on your preference.
- Click next.
- In the next Additional Info window, uncheck the “Use Controller…” box as we will be using minimal APIs in this example. Leave the “Authentication Type” as “None” (default).
- Make sure the “Enable Docker”, “Configure for HTTPS” and “Enable Open API Support” checkboxes are unchecked as we will not be using any of these features here.
- Click Create.
We’ll use this ASP.NET Core 7 Web API project to create minimal API endpoints and work with cancellation tokens.
What are cancellation tokens? When should we use them?
A CancellationToken is a simple object created by a CancellationTokenSource instance. When a CancellationTokenSource is canceled, all consumers of CancellationTokens are notified accordingly. In addition, the IsCancellationRequested property of the cancellation token instance is set to true, indicating that the CancellationTokenSource was canceled and the task was requested to be canceled.
You can use a CancellationToken to stop a long-running operation when the user cancels a request in the web browser. In other words, using a CancellationToken can help you prevent long-running requests from using resources when the user has paused or refreshed the webpage.
You can also use CancellationTokens to stop asynchronous tasks. In an asynchronous task, cancellation indicates that the task should finish executing its current activity. An asynchronous task receives a cancellation token and examines it to see if cancellation is requested. If this is the case, current operations should cease immediately.
Long-running requests in ASP.NET Core
When working on web applications, you may often use long-running tasks, ie database calls, file management, etc. When an object creates one or more long-running operations, it should propagate cancellation tokens to all those operations. Cancellation tokens should also be propagated to other internal operations.
Finally, the object that created the long-running operations—after a deadline or when a user stops a request—can propagate cancellation notification to these cancellation tokens. It should be noted that all long-running operations respect the cancel requirement, and the long-running operations must cancel in order for resources to be freed.
Listening for cancellation requests in ASP.NET Core
You can listen for cancellation requests by getting the value of the CancellationToken.IsCancellationRequested property, as shown in the following code snippet.
while(!cancellationToken.IsCancellationRequested)
{
//Write your code here to perform some operation
}
Another way to listen for cancellation requests is to call the ThrowIfCancellationRequested method, as shown in the code snippet below.
while(true)
{
//Write your code here to perform some operation
cancellationToken.ThrowIfCancellationRequested();
}
And you can listen for cancellation requests by registering a callback as shown in the code snippet below.
WebClient webClient = new WebClient();
cancellationToken.Register(() =>
{
webClient.CancelAsync();
});
Create a minimal API handler in ASP.NET Core
Now let’s simulate a long-running request and see how the cancellation works. First we try a long running request with no cancellation. Write the following section of code in the Program.cs file.
app.MapGet("/hello", async () =>
{
app.Logger.LogInformation("Request started at: "+DateTime.Now.ToLongTimeString());
await Task.Delay(TimeSpan.FromSeconds(5));
app.Logger.LogInformation("Request completed at: " + DateTime.Now.ToLongTimeString());
return "Success";
});
If you run this application and click on the /hello endpoint, you will see that the handler runs to completion even if you try to stop the request by refreshing the web browser as shown in Figure 1.
Use a CancellationToken in a minimal API handler
The following code listing shows how to inject a CancellationToken into our endpoint handler and pass that token to the Task.Delay method.
app.MapGet("/hello", async (CancellationToken token) =>
{
app.Logger.LogInformation("Request started at: " + DateTime.Now.ToLongTimeString());
await Task.Delay(TimeSpan.FromSeconds(5), token);
app.Logger.LogInformation("Request completed at: " + DateTime.Now.ToLongTimeString());
return "Success";
});
Now when you run the application and reach the /hello endpoint, refreshing the web browser will stop the request before the request completes. The logs show that the request never completes. Instead, a TaskCancelledException is thrown because the CancellationToken.IsCancellationRequested property is set to true.
The exception messages contain the trace information about the canceled request, as shown in Figure 2.
Checking the cancellation status in ASP.NET Core
You may often want to know if a cancellation has been requested for a cancellation token. You can check the cancellation status by examining the IsCancellationRequested property. The IsCancellationRequested property is true (ie, has a boolean value of true) if cancellation was requested for the token, false otherwise.
As mentioned above, the CancellationToken.ThrowIfCancellationRequested method throws an OperationCanceledException if the cancellation token instance has requested cancellation.
The following code snippet illustrates how the IsCancellationRequested property can be used to check whether the token has requested cancellation. If the request was canceled, an instance of OperationCanceledException is thrown.
if (token.IsCancellationRequested)
{
app.Logger.LogInformation("Request has been cancelled..");
throw new OperationCanceledException();
}
Using cancellation tokens is a best practice, but not always recommended in your controller action methods. If the request changes status, you don’t want such a request to be canceled. Cancellation tokens are mainly useful for long-running calls that consume significant resources when stopping the request has no side effects.
Finally, for the purposes of this article, we used Task.Delay to simulate a long-running task. In its place, you can substitute any long-running calls specific to your application’s needs, such as B. Database calls, network calls, file processing operations, downloading files from the Internet and so on.
Copyright © 2022 IDG Communications, Inc.