DEV Community

Cover image for A Small ASP.NET Core Improvement That Can Save Big Server Resources: `CancellationToken`
Rhuturaj Takle
Rhuturaj Takle

Posted on

A Small ASP.NET Core Improvement That Can Save Big Server Resources: `CancellationToken`

Summer Bug Smash: Smash Stories Submission 🐛🛹

This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry.

A Small ASP.NET Core Improvement That Can Save Big Server Resources: CancellationToken

🚀 The Improvement

During a recent review of our ASP.NET Core APIs, we noticed something that many teams—including ours—often overlook: we weren't passing CancellationToken through our API, service, and repository layers.

The application was working correctly. There were no errors, no failed requests, and nothing obviously broken.

However, from a scalability and resource-management perspective, there was room for improvement.

So we decided to implement CancellationToken support throughout the entire request pipeline.

🤔 Why Does CancellationToken Matter?

Whenever a client sends a request, there's always a chance they may:

  • Close the browser.
  • Refresh the page.
  • Lose network connectivity.
  • Cancel the request.
  • Hit a timeout.

Without a CancellationToken, the server has no way to know that the client is no longer waiting.

As a result, it may continue:

  • Executing database queries.
  • Calling external APIs.
  • Reading or writing files.
  • Performing CPU-intensive work.
  • Holding database connections until the operation completes.

The response is ultimately discarded because the client has already disconnected, but the server has still spent time and resources producing it.

With CancellationToken, ASP.NET Core automatically signals when a request has been cancelled. By passing that token through every async operation, your application can stop processing as early as possible and release resources immediately.

🔧 What We Changed

We updated every layer of our application to accept and propagate the same CancellationToken.

Instead of this:

public async Task<User> GetUserAsync(int id)
{
    return await _context.Users.FirstOrDefaultAsync(x => x.Id == id);
}
Enter fullscreen mode Exit fullscreen mode

We now do this:

public async Task<User> GetUserAsync(int id, CancellationToken cancellationToken)
{
    return await _context.Users
        .FirstOrDefaultAsync(x => x.Id == id, cancellationToken);
}
Enter fullscreen mode Exit fullscreen mode

And in the controller:

[HttpGet("{id}")]
public async Task<IActionResult> GetUser(
    int id,
    CancellationToken cancellationToken)
{
    var user = await _userService.GetUserAsync(id, cancellationToken);
    return Ok(user);
}
Enter fullscreen mode Exit fullscreen mode

The same token is passed through controllers, services, repositories, and EF Core operations.

📈 Benefits

After implementing this improvement, our APIs now:

  • Stop processing abandoned requests automatically.
  • Avoid unnecessary database work.
  • Free database connections sooner.
  • Reduce CPU and memory usage under load.
  • Scale more efficiently during peak traffic.
  • Follow ASP.NET Core asynchronous programming best practices.

💡 Takeaway

This wasn't about fixing a broken feature—it was about making a working application more efficient and production-ready.

CancellationToken is easy to skip because everything appears to work without it. But in real-world applications handling thousands of requests, properly supporting request cancellation helps avoid wasted work and improves overall server health.

If your ASP.NET Core project doesn't consistently pass CancellationToken through async methods, it's worth considering. It's a small change that can have a meaningful impact on the performance and scalability of your application.

Top comments (0)