Microsoft.Extensions.Hosting.BackgroundService
Overview
BackgroundService is an abstract base class in Microsoft.Extensions.Hosting used to create long-running, hosted background tasks in .NET applications.
It is commonly used in:
- Worker services (Windows Services, Linux systemd)
- APIs that need background jobs (emails, events, clean-up tasks)
- Message consumers (Kafka, RabbitMQ, Azure Service Bus)
- Scheduled tasks
- Pipelines and event processing
It integrates fully with:
- Dependency injection
- Logging
- IHost / IHostBuilder
- Graceful shutdown via CancellationToken
Architectural Purpose
A BackgroundService gives you a continuous or looping workflow that runs asynchronously in the background of your application until it is stopped.
You implement:
protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
This method runs once and should contain your background loop.
High-Level Architecture Diagram
flowchart TD
A[Host Web/Worker] --> B[BackgroundService Instance]
B -->|ExecuteAsync| C[Long-running Loop / Processing]
C --> D[External Services: Queues, APIs, DB, Files]
B --> E[CancellationToken for Shutdown]
Basic Example
Step 1: Create a BackgroundService
public class MyWorker : BackgroundService
{
private readonly ILogger<MyWorker> _logger;
public MyWorker(ILogger<MyWorker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1000, stoppingToken);
}
}
}
Step 2: Register in Program.cs (Minimal Hosting)
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<MyWorker>();
var app = builder.Build();
app.Run();
When to Use BackgroundService
Recommended For
- Polling external APIs
- Processing message queues (Kafka, RabbitMQ, Azure Service Bus)
- Data ingestion pipelines
- Scheduled tasks (cron-like behaviour)
- Periodic cache warmers
- Cleanup / maintenance tasks
- Long-running workflows
Not recommended for
- CPU-heavy pure computation → use
Task.Run+ thread pools - Short-lived tasks (just trigger them directly)
- Cross-process durable messaging (use Azure Functions, MassTransit, Hangfire, Quartz.NET, etc.)
Correct Pattern: Using an Async Loop
A good BackgroundService implementation should:
- Use a while loop
- Support cancellation
- Use Task.Delay or await async operations
- Avoid blocking threads
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
await DoWorkAsync(stoppingToken);
await Task.Delay(TimeSpan.FromSeconds(5), stoppingToken);
}
}
Proper Shutdown Handling
.NET stops services in this order:
- Sends cancellation to the
stoppingToken - Waits for
ExecuteAsyncto exit gracefully - Disposes the service
Always ensure:
- No infinite loops without cancellation checks
- No
Thread.Sleep(blocks shutdown) - No swallowed exceptions
Advanced Example — BackgroundService + Channels
Perfect for message pipelines (e.g., Kafka → Processor):
public class MessageProcessor : BackgroundService
{
private readonly ChannelReader<Message> _reader;
public MessageProcessor(Channel<Message> channel)
{
_reader = channel.Reader;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await foreach (var msg in _reader.ReadAllAsync(stoppingToken))
{
await ProcessAsync(msg);
}
}
}
Using BackgroundService with Timers (Cleaner Pattern)
.NET 6+ introduces PeriodicTimer:
var timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
while (await timer.WaitForNextTickAsync(stoppingToken))
{
await DoWorkAsync();
}
Advantages:
- More reliable than
Task.Delay - Built for periodic jobs
- Supports cancellation cleanly
10. Using BackgroundService in ASP.NET Core
Examples:
- Webhook processors
- Email dispatchers
- File archiving / cleanup jobs
- Metrics collectors
APIs remain responsive while work happens in the background.
11. Alternatives to BackgroundService
BackgroundService vs IHostedService
BackgroundService implements IHostedService — it’s a convenience class.
| Aspect | IHostedService | BackgroundService |
|---|---|---|
| Code | Boilerplate | Minimal |
| StartAsync/StopAsync | Manual | Automatic |
| Loop logic | Manual | Built into ExecuteAsync |
Always prefer BackgroundService unless you need very custom start/stop behaviour.
BackgroundService vs Windows Service
| Feature | BackgroundService | Windows Service |
|---|---|---|
| Cross-platform | ✔ | ✘ |
| DI support | ✔ | ✘ |
| Hosting model | Inside .NET Host | OS-native service |
| Use case | Applications | OS-level background services |
You can host a BackgroundService AS a Windows Service using UseWindowsService().
BackgroundService vs Hangfire / Quartz.NET
If you need:
| Feature | BackgroundService | Hangfire / Quartz |
|---|---|---|
| Cron scheduling | Manual | Built-in |
| Persistence | ✔ if you write it | ✔ out-of-the-box |
| Distributed workers | No | Yes |
| GUI dashboards | No | Yes |
Use Hangfire/Quartz for distributed or scheduled jobs. Use BackgroundService for internal, in-memory, continuous processing.
Advantages & Disadvantages
Advantages
- Simple to use
- Built into .NET runtime
- First-class async support
- Graceful shutdown handling
- Integrates with DI and logging
- Cross-platform (Windows/Linux/macOS)
- Ideal for background pipelines, queues, and periodic jobs
Disadvantages
- No persistence — jobs are lost if the service crashes
- No built-in scheduling (must implement manually)
- Can be misused for CPU-heavy tasks
- Not suitable for distributed workloads
- Harder to test than normal services (needs cancellation orchestration)
Summary
BackgroundService is an abstract base class in .NET used to implement long-running, asynchronous background tasks integrated with the .NET hosting model.
You override ExecuteAsync, implement an asynchronous loop, handle cancellation, and register your service using DI. It supports graceful shutdown, works cross-platform, and is ideal for pipelines, message processing, cleanup tasks, and continuous workflows inside a .NET app.
Compared to IHostedService, it removes boilerplate. It is not designed for scheduled or durable tasks — for that, use Hangfire or Quartz.NET. In modern .NET (including .NET 10), BackgroundService remains the standard for internal background workers.
See Also
- System.Threading.Channels Wiki page.
- PeriodicTimer Wiki page.
Further Reading
- Microsoft Docs — Background services https://learn.microsoft.com/aspnet/core/fundamentals/host/hosted-services
- Worker service template https://learn.microsoft.com/dotnet/core/extensions/workers
- PeriodicTimer documentation https://learn.microsoft.com/dotnet/api/system.threading.periodictimer