Introduction
Not every task in an application should run as part of an HTTP request. Some operations take a long time to complete, while others need to run continuously in the background. Examples include processing emails, generating reports, synchronizing data, cleaning temporary files, or consuming messages from a queue.
Running these tasks directly inside a controller or API endpoint can slow down your application and create a poor user experience. ASP.NET Core provides the BackgroundService class to solve this problem.
BackgroundService allows you to run long-running tasks independently of incoming HTTP requests while keeping your application responsive and scalable.
In this article, you'll learn how BackgroundService works, when to use it, and the best practices for building reliable background processes in ASP.NET Core.
What Is BackgroundService?
BackgroundService is an abstract class provided by ASP.NET Core for implementing hosted services that run in the background.
Unlike a controller, a background service starts when the application starts and continues running until the application stops.
Some common use cases include:
Sending emails
Processing message queues
Importing data from external systems
Scheduled cleanup tasks
Generating reports
Monitoring application health
Processing uploaded files
Since these operations run independently, they don't block incoming user requests.
Creating a Background Service
Creating a background service is simple. Create a class that inherits from BackgroundService.
using Microsoft.Extensions.Hosting;
public class WorkerService : BackgroundService
{
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
Console.WriteLine("Background task is running...");
await Task.Delay(5000, stoppingToken);
}
}
}
The ExecuteAsync method contains the logic that runs continuously until the application shuts down.
Registering the Background Service
After creating the service, register it with the dependency injection container.
builder.Services.AddHostedService<WorkerService>();
When the application starts, ASP.NET Core automatically starts the background service.
No additional configuration is required.
Understanding the Cancellation Token
A background service should always respond gracefully when the application is shutting down.
ASP.NET Core provides a CancellationToken that signals when the service should stop.
Example:
while (!stoppingToken.IsCancellationRequested)
{
await ProcessDataAsync();
await Task.Delay(10000, stoppingToken);
}
Checking the cancellation token ensures that the application can shut down cleanly without leaving unfinished operations.
Processing Queue Messages
One of the most common uses of BackgroundService is processing messages from a queue.
A typical workflow looks like this:
A user submits a request.
The application places a message in a queue.
The API immediately returns a response.
The background service reads the message.
The task is processed asynchronously.
This approach improves responsiveness because users don't have to wait for lengthy operations to complete.
Using Dependency Injection
Background services can use other application services through dependency injection.
For example:
public class WorkerService : BackgroundService
{
private readonly ILogger<WorkerService> _logger;
public WorkerService(ILogger<WorkerService> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(
CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker is running.");
await Task.Delay(5000, stoppingToken);
}
}
}
This makes it easy to use logging, database services, or other application components inside the background service.
Handle Exceptions Properly
A background service should never stop unexpectedly because of an unhandled exception.
Instead, catch exceptions, log them, and continue processing when appropriate.
try
{
await ProcessOrdersAsync();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Proper exception handling improves application reliability and simplifies troubleshooting.
Avoid Blocking Operations
Background services should use asynchronous methods whenever possible.
Instead of:
Thread.Sleep(5000);
Use:
await Task.Delay(5000, stoppingToken);
Asynchronous operations free application threads to handle other work, improving scalability.
Real-World Example
Imagine an online shopping application.
When a customer places an order:
The API saves the order.
A message is added to a queue.
The API immediately returns a success response.
A background service processes the order.
The service sends a confirmation email.
Inventory is updated.
A shipping request is created.
The customer receives an immediate response while the remaining tasks continue in the background.
Best Practices
When using BackgroundService in ASP.NET Core, follow these recommendations:
Keep background tasks independent of HTTP requests.
Always use the provided CancellationToken.
Prefer asynchronous operations over blocking calls.
Handle exceptions to prevent unexpected service termination.
Use dependency injection instead of creating services manually.
Log important events and errors for easier monitoring.
Avoid performing CPU-intensive work on the main application thread.
Monitor background service performance and resource usage in production.
Conclusion
BackgroundService provides a clean and reliable way to run long-running tasks in ASP.NET Core applications. By moving work such as email processing, queue consumption, report generation, and scheduled maintenance outside the request pipeline, you can improve application responsiveness and deliver a better user experience.
When combined with dependency injection, asynchronous programming, and proper error handling, BackgroundService becomes a powerful tool for building scalable and maintainable applications. By following the best practices outlined in this article, you can create background processes that run efficiently and reliably in production environments.