Joydip Kanjilal
Contributor

How to use cancellation tokens in ASP.NET Core 7

how-to
Oct 05, 20227 mins
C#Development Libraries and FrameworksMicrosoft .NET

Take advantage of cancellation tokens in ASP.NET Core to allow long running operations to be cancelled gracefully and keep applications responsive.

yes no neon sign cancel buzzwords just say no red neon by sarawuth702 getty
Credit: sarawuth702 / Getty Images

Although ASP.NET Core 7 is the latest version of Microsoft’s open source web application development framework, it takes advantage of countless significant features from previous versions of .NET. One of these significant features is cancellation tokens, which provide a way of gracefully handling multi-threaded applications.

When working with ASP.NET Core applications, it is good practice to make long running operations (such as a database query or background process) cancelable, either after a certain length of time or upon user request, so that the application can release resources and remain responsive. Here’s where cancellation tokens come into play.

This article discusses cancellation tokens, why they are useful, and how to use them in minimal API handlers in ASP.NET Core. To work with the code examples provided in this article, you should have Visual Studio 2022 Preview installed in your system. If you don’t already have a copy, you can download Visual Studio 2022 here.

Create an ASP.NET Core 7 minimal Web API project in Visual Studio 2022

First off, let’s create an ASP.NET Core minimal API project in Visual Studio. Following these steps will create a new ASP.NET Core 7 Web API project in Visual Studio 2022 Preview:

  1. Launch the Visual Studio 2022 Preview IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “ASP.NET Core Web API” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window, specify the name and location for the new project.
  6. Optionally check the “Place solution and project in the same directory” check box, depending on your preferences.
  7. Click Next.
  8. In the “Additional Information” window shown next, uncheck the check box that says “Use controllers…” since we’ll be using minimal APIs in this example. Leave the “Authentication Type” as “None” (default).
  9. Ensure that the check boxes “Enable Docker,” “Configure for HTTPS,” and “Enable Open API Support” are unchecked as we won’t be using any of those features here.
  10. 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 lightweight object created by a CancellationTokenSource instance. When a CancellationTokenSource is canceled, all consumers of CancellationTokens are notified accordingly. Additionally, the IsCancellationRequested property of the cancellation token instance is set to true, indicating that the CancellationTokenSource has been canceled and cancellation of the task has been requested.

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 stop long running requests from using resources when the user has stopped or refreshed the web page.

You can use CancellationTokens to stop async tasks as well. In an async task, cancellation indicates that the task should cease performing its current activity. An async task receives a cancellation token and examines it to see if a cancellation is requested. If so, the current operation should cease immediately.

Long running requests in ASP.NET Core

When working on web applications, you might often make use of long running tasks, i.e., database calls, file handling, etc. When an object creates one or more long running operations, it should pass cancellation tokens to all of those operations. Cancellation tokens should also be passed to other internal operations.

Eventually, the object that created the long running operations may — after a time deadline is reached, or when a user stops a request — propagate a cancellation notification to these cancellation tokens. It should be noted that all long running operations must respect the cancellation request and cancel the long running operations so that resources can be released.

Listening for cancellation requests in ASP.NET Core

You can listen for cancellation requests by polling the value of the CancellationToken.IsCancellationRequested property as shown in the code snippet given below.

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 given 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 following code snippet.

WebClient webClient = new WebClient();   
cancellationToken.Register(() =>
{
    webClient.CancelAsync();
});

Create a minimal API handler in ASP.NET Core

Let’s now simulate a long running request and see how cancellation works. First we’ll try a long running request without cancellation. Write the following piece 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";
});

When you execute this application and hit the /hello endpoint, you will see that the handler executes in its entirety even if you try to stop the request by refreshing the web browser as shown in Figure 1.

cancellation tokens 01 IDG

Figure 1: Without cancellation, the handler executes in its entirety even if the request is aborted by the user.

Use a CancellationToken in a minimal API handler

The following code listing shows how you can inject a CancellationToken into our endpoint handler and pass this 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 execute the application and hit the /hello endpoint, refreshing the web browser before the request completes will stop the request. You’ll see from the logs that the request never completes. Instead, a TaskCancelledException will be thrown because the CancellationToken.IsCancellationRequested property will be set to true.

The exception messages will contain the trace information on the aborted request as shown in Figure 2.

cancellation tokens 02 IDG

Figure 2: When cancellation has been used in the handler code, a request that is aborted midway will not complete.

Checking cancellation state in ASP.NET Core

You might often want to know if cancellation has been requested on a cancellation token. You can check the cancellation state by examining the IsCancellationRequested property. The IsCancellationRequested property will be true (i.e., will have a boolean value of true) if cancellation has been requested on the token, false otherwise.

As mentioned above, the CancellationToken.ThrowIfCancellationRequested method will throw an OperationCanceledException if the cancellation token instance has requested cancellation.

The following code snippet illustrates how the IsCancellationRequested property can be used to check if the token has requested cancellation. If the request has been cancelled, an instance of OperationCanceledException is thrown.

if (token.IsCancellationRequested)
{
    app.Logger.LogInformation("Request has been cancelled..");
    throw new OperationCanceledException();
}

Using cancellation tokens is a good practice, but it is not always recommended in your controller action methods. If the request modifies the state, you will not want such a request to be cancelled. Cancellation tokens are useful mainly for long running calls that consume significant resources, when stopping the request will not have any side effects.

Finally, for the purposes of this article, we used Task.Delay to simulate a long running operation. In its place, you can substitute any long running calls specific to your application’s requirements such as database calls, network calls, file handling operations, downloading files from the internet, and so on.

Joydip Kanjilal
Contributor

Joydip Kanjilal is a Microsoft Most Valuable Professional (MVP) in ASP.NET, as well as a speaker and the author of several books and articles. He received the prestigious MVP award for 2007, 2008, 2009, 2010, 2011, and 2012.

He has more than 20 years of experience in IT, with more than 16 years in Microsoft .Net and related technologies. He has been selected as MSDN Featured Developer of the Fortnight (MSDN) and as Community Credit Winner several times.

He is the author of eight books and more than 500 articles. Many of his articles have been featured at Microsoft’s Official Site on ASP.Net.

He was a speaker at the Spark IT 2010 event and at the Dr. Dobb’s Conference 2014 in Bangalore. He has also worked as a judge for the Jolt Awards at Dr. Dobb's Journal. He is a regular speaker at the SSWUG Virtual Conference, which is held twice each year.

More from this author