Cancellation Tokens in ASP.NET Core

Merwan Chinta
CodeNx
Published in
3 min readFeb 19, 2024

--

Cancellation tokens in ASP.NET Core serve a practical purpose: they stop the server from doing unnecessary work. This is essential in web development, where resources are finite and user patience is even more so. A well-designed API takes both into account.

Let’s walk through an example of how to implement cancellation tokens in a Minimal API and simulate a client triggering a cancellation.

Cancellation Token Explained
Cancellation Token Explained — Image source: Created by Author

Code Example

using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Hosting;
using System.Threading;
using System.Threading.Tasks;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/heavy-operation", async (CancellationToken ct) =>
{
// Pretend we have a heavy operation that can take a long time
bool operationCompleted = await HeavyOperationAsync(ct);

if (ct.IsCancellationRequested)
{
return Results.StatusCode(499); // Client closed the request
}

return operationCompleted ? Results.Ok() : Results.StatusCode(500);
});

async Task<bool> HeavyOperationAsync(CancellationToken cancellationToken)
{
// Simulate a task that checks the cancellation token periodically
for (int i = 0; i < 5; i++)
{
if (cancellationToken.IsCancellationRequested)
{
// Clean up if needed, then break
return false;
}
await Task.Delay(1000); // Simulate work by delaying
}
return true;
}

app.Run();

In this example, we define an endpoint `/heavy-operation` that performs a simulated long-running operation. The endpoint accepts a CancellationToken (ct) as an argument, which is a standard feature in ASP.NET Core.

The HeavyOperationAsync method is designed to do its work in a loop, checking cancellationToken.IsCancellationRequested at each iteration. If the cancellation is requested, the method exits early. This pattern ensures that the server can stop processing as soon as the client loses interest, freeing up resources.

Client Code Example

// Example client-side code to call the API and cancel the request
using var cts = new CancellationTokenSource();
var httpClient = new HttpClient();

// Start the request
var task = httpClient.GetAsync("http://localhost:5000/heavy-operation", cts.Token);

// Cancel the request after 3 seconds
await Task.Delay(3000);
cts.Cancel();

try
{
await task; // This will throw if the operation was canceled
}
catch (TaskCanceledException)
{
Console.WriteLine("Request was canceled.");
}

On the client side, we simulate making a request to the server and then canceling it after a short delay. The HttpClient accepts a CancellationTokenSource (cts) that can trigger a cancellation from the client end.

When cts.Cancel() is called, the server’s cancellation token is signaled, and if the server is in the middle of HeavyOperationAsync, it stops processing and exits the loop. The client’s task throws a TaskCanceledException, which we catch to confirm that the request was indeed canceled.

This example illustrates the use of cancellation tokens in ASP.NET Core to write efficient and responsive APIs. By incorporating cancellation tokens into your API design, you’re ensuring that your application respects both the client’s time and the server’s resources, making for a well-rounded and efficient web service.

Where is CancellationToken majorly used?

  • Background Jobs: For operations that run in the background, such as batch processing or data import/export tasks, cancellation tokens allow these jobs to be terminated if they’re no longer needed.
  • Web Requests: In web applications, to abort ongoing HTTP requests when the user navigates away from a page or cancels the request.
  • User-Initiated Processes: In scenarios where a user can start a process that takes considerable time and they need the ability to cancel it, such as report generation or complex queries.
  • Timeout Operations: For operations that should be terminated if they exceed a certain execution time, ensuring that resources are not held indefinitely.
  • Resource-Intensive Computations: In applications performing heavy calculations or data processing which may need to be halted if the result is no longer required.
  • Parallel Tasks: When running multiple tasks in parallel and one fails or a certain condition is met, other tasks can be canceled to avoid unnecessary processing.
  • Workflow Operations: In workflow engines, to cancel a long-running workflow or a specific activity within a workflow.
  • Streaming Operations: For streaming data to a client, cancellation tokens can be used to stop the data stream if the client disconnects or stops consuming the data.

What can be explored further?

Further exploration could include advanced patterns for cancellation token usage in distributed systems and understanding how to handle complex scenarios with linked cancellation tokens for coordinated cancellation across multiple tasks or services.

I trust this information has been valuable to you. 🌟 Wishing you an enjoyable and enriching learning journey!

📚 For more insights like these, feel free to follow 👉 Merwan Chinta

--

--

Merwan Chinta
CodeNx

🚧 Roadblock Eliminator & Learning Advocate 🖥️ Software Architect 🚀 Efficiency & Performance Guide 🌐 Cloud Tech Specialist