Modern web applications frequently execute long-running operations such as database queries, file uploads, report generation, external API calls, and background processing. However, users may close their browser, mobile devices may lose connectivity, or reverse proxies may terminate requests before these operations complete.
Without proper cancellation support, the application continues processing requests that no longer have an active client, wasting CPU, memory, database connections, and network resources. ASP.NET Core provides built-in support for CancellationToken, enabling applications to stop unnecessary work as soon as a request is cancelled.
Rather than ignoring cancelled requests, this article explains how to use CancellationToken throughout an ASP.NET Core application to improve scalability, responsiveness, and resource utilization.
Note: Cancellation tokens are cooperative. They signal that work should stop, but your code must explicitly observe the token and terminate gracefully.
Why Cancellation Tokens Matter
Ignoring cancelled requests can lead to:
Wasted CPU cycles
Unnecessary database queries
Long-running background operations
Connection pool exhaustion
Increased memory usage
Poor application scalability
Supporting cancellation allows the application to free resources immediately when work is no longer needed.
Common Scenarios for Cancellation
Cancellation tokens are commonly used with:
Almost every asynchronous operation in ASP.NET Core supports cancellation.
Request Cancellation Flow
flowchart LR
A[Client Request]
B[ASP.NET Core]
C[Controller]
D[Service]
E[(Database)]
A --> B
B --> C
C --> D
D --> E
A -. Client Disconnect .-> B
B --> F[CancellationToken Triggered]
F --> D
D --> C
C --> B
Once the client disconnects, ASP.NET Core signals the cancellation token, allowing ongoing operations to stop.
Receiving a CancellationToken
ASP.NET Core automatically injects a cancellation token into controller actions.
[HttpGet]
public async Task<IActionResult> GetProducts(
CancellationToken cancellationToken)
{
var products =
await service.GetProductsAsync(
cancellationToken);
return Ok(products);
}
The token is automatically linked to the lifetime of the HTTP request.
Passing the Token Through Services
Pass the token through every application layer.
public async Task<List<Product>>
GetProductsAsync(
CancellationToken cancellationToken)
{
return await repository
.GetAllAsync(cancellationToken);
}
Avoid creating new cancellation tokens unless necessary.
Using Cancellation with EF Core
Entity Framework Core supports cancellation.
var products =
await context.Products
.ToListAsync(cancellationToken);
If the request is cancelled, EF Core stops executing the query whenever possible.
Using Cancellation with HttpClient
Forward the cancellation token to outbound HTTP calls.
var response =
await httpClient.GetAsync(
"/products",
cancellationToken);
This prevents waiting for external services after the client has already disconnected.
Cancelling Long-Running Operations
Check the token periodically during lengthy processing.
for (int i = 0; i < 100; i++)
{
cancellationToken.ThrowIfCancellationRequested();
await ProcessItemAsync(i);
}
The operation exits immediately when cancellation is requested.
Background Service Cancellation
Hosted services automatically receive a cancellation token.
public class Worker : BackgroundService
{
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await ProcessQueueAsync();
await Task.Delay(
1000,
stoppingToken);
}
}
}
The worker stops gracefully during application shutdown.
Cancellation Workflow
sequenceDiagram
participant Client
participant API
participant Database
Client->>API: Request
API->>Database: Query
Client-->>API: Disconnect
API->>Database: Cancel Query
Database-->>API: Operation Cancelled
API-->>Client: Connection Closed
Cancellation prevents unnecessary work after the client is no longer waiting for a response.
Operations That Support Cancellation
| Operation | Supports Cancellation |
|---|
| EF Core Queries | ✅ |
| HttpClient | ✅ |
| File Streams | ✅ |
| Task.Delay | ✅ |
| BackgroundService | ✅ |
| ASP.NET Core MVC | ✅ |
Most modern .NET APIs include overloads that accept a CancellationToken.
Common Production Mistakes
| Problem | Root Cause |
|---|
| Database queries continue after disconnect | Cancellation token not passed to EF Core |
| External API calls continue running | Token not forwarded to HttpClient |
| High CPU usage | Long loops ignore cancellation |
| Background services hang during shutdown | IsCancellationRequested never checked |
| Resource exhaustion | Cancelled requests continue processing |
| Unexpected exceptions | OperationCanceledException not handled appropriately |
Many scalability issues are caused by ignoring cancellation rather than expensive operations themselves.
Best Practices
Accept a CancellationToken in every asynchronous endpoint.
Pass the token through every application layer.
Use asynchronous APIs that support cancellation.
Check cancellation during long-running loops.
Handle OperationCanceledException appropriately.
Test cancellation behavior under production-like workloads.
Avoid creating unnecessary linked cancellation tokens.
Common Anti-Patterns
Avoid these common mistakes:
Ignoring the provided cancellation token.
Creating a new CancellationTokenSource for every request.
Catching and suppressing OperationCanceledException without understanding the cause.
Performing expensive cleanup after cancellation.
Blocking threads with synchronous code.
Assuming cancellation immediately terminates execution.
FAQ
Does ASP.NET Core automatically cancel requests?
Yes. When the client disconnects or the request is aborted, ASP.NET Core signals the associated CancellationToken. Your application must observe that token and stop processing.
Should every asynchronous method accept a CancellationToken?
In most cases, yes. Passing the token through the application allows cancellation to propagate naturally from the HTTP request to lower layers.
Is OperationCanceledException an error?
Not usually. It indicates that an operation ended because cancellation was requested. In many scenarios, it represents expected behavior rather than an application failure.
Does cancellation roll back database transactions?
Cancellation stops ongoing work when supported by the underlying provider, but transaction rollback depends on how the transaction is managed. Ensure transactions are handled correctly to maintain data consistency.
Conclusion
Cancellation tokens are a fundamental part of building scalable and efficient ASP.NET Core applications. By propagating cancellation through controllers, services, database operations, and external API calls, you can avoid wasting resources on work that no longer benefits the client.
Implementing cancellation consistently not only improves application performance but also enhances reliability during client disconnects, deployment events, and long-running operations, making your applications better prepared for production workloads.