Cancellation Token in C# - Explained
Tags: csharp, dotnet, webdev, programming
Published: 2023-12-17 14:57:58

Have you come across any scenario where you started long-running asynchronous tasks in C# but want to cancel in the middle of the execution?

Either the user wants to cancel or the application itself is required to cancel the operation, it is a good idea to cancel the resource-heavy long-running operations (logic built using a database, report generation, etc.) gracefully.

Let's discuss about cancellation token in c# which is responsible for canceling tasks.


## What is the Cancellation token in C#?

A cancellation token in C# is represented by the `CancellationToken` struct is a way to notify an operation or task that should be cancelled cooperatively.

A `CancellationToken` enables cooperative cancellation between threads, thread pool work items, or Task objects.

## Why do you need a Cancellation token?

To enable cooperative cancellation of tasks/operations that might be no longer needed or take a long time to complete.

Cooperative cancellation means that the operation can check the cancellation token periodically and gracefully stop if it has been canceled, rather than being aborted abruptly.

This allows the operation to release any resources, close any files, or perform any other cleanup before exiting.

## How to create a cancellation token in C#?

You can create a cancellation token by using a `CancellationTokenSource` object, which manages the cancellation tokens retrieved from its `CancellationTokenSource.Token` property.

```csharp
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
CancellationToken cancellationToken = cancellationTokenSource.Token;
```

You can then pass the cancellation token to any threads, tasks, or operations that should receive the cancellation notification.

## How to cancel the asynchronous operation?

You can either use the `Cancel()` or `CancelAfter()` method from `CancellationTokenSource` to cancel the token.

```csharp
cancellationTokenSource.Cancel(); //Cancel immediately
cancellationTokenSource.CancelAfter(1000); //Cancel after given time
```

If you want to cancel the asynchronous APIs, the route endpoint should use the `CancellationToken` delegate handler as mentioned below. Your code should check for a `token.IsCancellationRequested` status periodically and acts based on the `true/false` value.

```csharp
app.MapGet("/ApiTest", async (CancellationToken token)
```

## How do you know the operation is cancelled?

`CancellationToken` has a property called `IsCancellationRequested` returns true if the token has been cancelled.

You can also use the `ThrowIfCancellationRequested` method to throw an OperationCanceledException if the token has been cancelled.

## How to use cancellationtoken in C#?

The asynchronous operations must periodically check for `cancellationToken.IsCancellationRequested` is `true`. If true, you should write your logic to gracefully exit all the long-running processes.

```csharp
while (!cancellationToken.IsCancellationRequested)
{
    //Long running operations here. 
}
```

Sometimes the `OperationCanceledException` will be thrown, hence introduce the try-catch block to handle the exceptions.

```csharp
try
{
    //Operations that might throw OperationCanceledException on cancel
}
catch (OperationCanceledException)
{
    //Handle the cancellation
}
```

Do the cleanup activities when `cancellationToken.IsCancellationRequested` true or inside catch block of `OperationCanceledException`. You may also use `CancellationToken.Register()` to register your custom cleanup logic as below, which will be executed once the token is cancelled.

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

### Cancellationtoken example in c# (using WebAPI)

```csharp
app.MapGet("/ApiTest", async (CancellationToken token) =>
{
    var result = await DoWorkAsync(token);
    return Results.Ok(result);
})
.WithName("ApiTest")
.WithOpenApi();

static async Task<string> DoWorkAsync(CancellationToken cancellationToken)
{
    try
    {
        // A long-running operation like database, business logics
        await Task.Delay(5000, cancellationToken);
        return "Operation completed.";
    }
    catch (OperationCanceledException ex)
    {
        return "Operation canceled. (No output to client)";
    }
}
```

* If the above API is executed without cancellation, it will return the "Operation completed." message.
    
* If the above API is cancelled, it will cancel the operation from `DoWorkAsync` method as well. Please note that no output will be returned to the client upon cancellation.
    

### Cancellationtoken example using console app

```csharp
using System;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        // Create a cancellation token source
        CancellationTokenSource cts = new CancellationTokenSource();

        // Pass the cancellation token to an asynchronous method
        DoWorkAsync(cts.Token);

        // Wait for user input to cancel the operation
        Console.WriteLine("Press any key to cancel...");
        Console.ReadKey();

        // Cancel the operation by calling Cancel() on the cancellation token source
        cts.Cancel();

        Console.WriteLine("Operation canceled.");
        Console.ReadKey();
    }

    static async void DoWorkAsync(CancellationToken cancellationToken)
    {
        try
        {
            // Simulate some long-running operation
            await Task.Delay(5000, cancellationToken);

            // Check if cancellation has been requested
            if (cancellationToken.IsCancellationRequested)
            {
                Console.WriteLine("Operation canceled.");
            }
            else
            {
                Console.WriteLine("Operation completed.");
            }
        }
        catch (OperationCanceledException)
        {
            Console.WriteLine("Operation canceled.");
        }
    }
}
```

Please note that the above code is auto-generated using AI.

## General recommendations

* Check the cancellation token periodically inside the long-running process. If cancelled, exit the process after handling necessary activities like closing database connections, releasing external resources, etc.
    
* Wherever necessary, pass the cancellation token to all the asynchronous methods which can be cancelled at a later time.
    
* Know when you’ve passed the point of no cancellation. Sometimes you may start changing the state of an object in the database and cancellation might lead to data inconsistency or other serious issues.
    
* **Don’t throw OperationCanceledException after you’ve completed the work,** just because the token was signalled.
    

### Summary

You should now understand how to use CancellationToken in C# to cancel the long-running operations when the request is cancelled. This will help us to save server resources and improve the application performance.

> If you enjoyed this post and want to get more valuable tips and insights on .NET/C#, don’t forget to subscribe to my newsletter [https://rajasekar.dev/newsletter](https://rajasekar.dev/newsletter) and get notified whenever I publish a new article. 

### References

[Recommended patterns for CancellationToken - Developer Support (microsoft.com)](https://devblogs.microsoft.com/premier-developer/recommended-patterns-for-cancellationtoken/)

[How to Cancel a Task in C# using Cancellation Token - Dot Net Tutorials](https://dotnettutorials.net/lesson/how-to-cancel-a-task-in-csharp/)

[Using a CancellationToken in .NET Core Web API | by Danielle | Medium](https://danielledevblog.medium.com/using-a-cancellationtoken-in-net-core-web-api-9779c39596d5)

[Why Do You Need a Cancellation Token in C# for Tasks? | HackerNoon](https://hackernoon.com/why-do-you-need-a-cancellation-token-in-c-for-tasks)