Efficient Resource Management in .NET: A Deep Dive into CancellationToken

Have you ever wondered what happens to your long-running backend task when a user suddenly closes their browser or cancels a request? Without proper handling, your server might continue to burn CPU cycles and database resources for a request that no one is listening to anymore.
In this article, we’ll explore how to bridge the gap between your Angular frontend and ASP.NET Core backend using the power of CancellationToken.
The Core Concept: What is a CancellationToken? 🛡️ Think of a CancellationToken as a "kill signal." When the source of a request (the client) decides to stop waiting, it sends a signal through the pipeline. Your code’s job is to listen for this signal and stop whatever it’s doing as quickly as possible.
Setting Up the Pipeline: From Angular to Database 🧬 For cancellation to work effectively, the token must travel through every layer of your application.
Step 1: Angular (The Trigger)
When you use Angular’s HttpClient and a user navigates away or unsubscribes from the observable, the browser aborts the HTTP request.
Pro Tip: Use the | async pipe in your templates. It automatically handles the unsubscription when the component is destroyed.
Step 2: ASP.NET Core Controller
The framework is smart enough to detect when a client disconnects. It can automatically inject a token into your controller method.
[HttpGet("data")]
public async Task GetData(CancellationToken ct)
{
// Pass the token 'ct' to your service layer
var result = await _service.GetLargeDataAsync(ct);
return Ok(result);
}
Step 3: The Service Layer & Database
Always pass the token to your database drivers (like EF Core).
public async Task GetLargeDataAsync(CancellationToken ct)
{
// EF Core will stop the query execution if 'ct' is cancelled
return await _context.Books.ToListAsync(ct);
}
3. Advanced Strategy: Linked Tokens (User + Timeout) ⏳ Sometimes, you want to cancel a task not just because the user left, but because it’s taking too long. This is where Linked Tokens come in.
public async Task GetBooksWithTimeoutAsync(CancellationToken userToken)
{
using var timeoutSource = new CancellationTokenSource(TimeSpan.FromSeconds(10));
using var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(userToken, timeoutSource.Token);
try
{
return await _context.Books.ToListAsync(linkedSource.Token);
}
catch (OperationCanceledException)
{
if (timeoutSource.Token.IsCancellationRequested)
// Handle Timeout logic here
throw;
}
}
4. What about Write Operations? (Insert/Update) ✍️ Be careful! Cancelling an Update or Insert query mid-way can lead to Partial Success, leaving your data in an inconsistent state.
Solution: Always use Transactions. If a CancellationToken throws an exception, catch it and ensure the transaction is rolled back to keep your data safe.
Best Practices Summary 💡
Always Pass the Token: Don't break the chain.
Last Parameter: Always place CancellationToken as the last parameter in your methods.
Dispose the Source: Always use using blocks for CancellationTokenSource to avoid memory leaks.
Conclusion
Implementing CancellationToken isn't just about saving resources; it's about building professional, resilient, and high-performance applications. Start passing your tokens today!