A crucial prerequisite for contemporary ASP.NET Core applications is background processing, particularly for those that use microservices. Background services are crucial for tasks like email sending, Kafka message processing, cron-type processes, and managing lengthy workflows.
With the introduction of the Generic Host and robust improvements in .NET 6, 7, and 8, ASP.NET Core now provides powerful patterns through:
- IHostedService
- BackgroundService
- Worker Service templates
This article dives deep into how to design, build, and optimize background services for production.
Worker Services vs Hosted Services: What’s the Difference?
Feature | IHostedService | BackgroundService | Worker Service Template |
Interface-based |
Yes |
Yes (abstracts IHostedService) |
Yes (project template-based) |
Long-running support |
Needs manual implementation |
Provides an infinite loop (ExecuteAsync) |
Yes |
Best for |
Short-lived or event-based tasks |
Long-running background jobs |
Standalone background apps |
Setting Up a Worker Service Project
You can create a worker service using.
dotnet new worker -n EmailBackgroundService
This creates a ready-to-run worker template using the Generic Host.
The Program.cs in .NET 8+ is minimal.
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices((context, services) =>
{
services.AddHostedService<EmailSenderWorker>();
})
.Build();
await host.RunAsync();
Creating a Custom BackgroundService
Here’s a simple example of a background worker.
public class EmailSenderWorker : BackgroundService
{
private readonly ILogger<EmailSenderWorker> _logger;
public EmailSenderWorker(ILogger<EmailSenderWorker> logger)
{
_logger = logger;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Sending queued emails at: {time}", DateTimeOffset.Now);
await SendPendingEmails();
await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
}
}
private Task SendPendingEmails()
{
// Implement actual email logic here
return Task.CompletedTask;
}
}
Advanced Hosted Services with IHostedService
When you need fine-grained control over start/stop behavior (e.g., for message queue consumers).
public class KafkaConsumerService : IHostedService
{
public Task StartAsync(CancellationToken cancellationToken)
{
// Connect to Kafka and begin consuming
return Task.Run(() => ConsumeMessages(cancellationToken), cancellationToken);
}
public Task StopAsync(CancellationToken cancellationToken)
{
// Cleanup, disconnect
return Task.CompletedTask;
}
private void ConsumeMessages(CancellationToken cancellationToken)
{
// Poll Kafka and process messages
}
}
Managing Multiple Background Services
You can register multiple services easily.
services.AddHostedService<EmailSenderWorker>();
services.AddHostedService<KafkaConsumerService>();
services.AddHostedService<DataSyncWorker>();
Each runs independently inside the host.
Handling Exceptions & Graceful Shutdown
To avoid crashing the entire app due to unhandled exceptions in workers.
try
{
await SomeBackgroundTask();
}
catch (Exception ex)
{
_logger.LogError(ex, "An error occurred.");
}
For graceful shutdown, ensure your workers respond to the CancellationToken from ExecuteAsync.
Dependency Injection in Background Services
Services are injected normally.
public class DataSyncWorker : BackgroundService
{
private readonly IDataService _dataService;
public DataSyncWorker(IDataService dataService)
{
_dataService = dataService;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
await _dataService.SyncExternalData();
}
}
Scheduling and Cron-like Jobs
For scheduled tasks, consider:
- Quartz.NET for CRON jobs.
- Hangfire for background jobs with retry support.
- Or a Timer-based service with Task.Delay.
Example using the Cronos package.
var cron = CronExpression.Parse("0 */5 * * * *");
var next = cron.GetNextOccurrence(DateTimeOffset.Now);
Logging, Metrics & Observability
Integrate with:
- Serilog / Seq for structured logging
- Prometheus for metrics
- OpenTelemetry for traces and spans
Production Tips
Always handle exceptions gracefully
- Use scoped services inside BackgroundService via IServiceScopeFactory
- Monitor using health checks (IHealthCheck)
- Separate retry logic (e.g., use Polly)
- Set max concurrency (e.g., in queues) to prevent overload
Conclusion
ASP.NET Core’s Hosted Services and Worker Services provide powerful primitives for executing background tasks in a clean, reliable, and scalable way. Whether you're building message consumers, email dispatchers, or data processors, background services allow you to decouple, scale, and manage your application’s background logic like a pro. Happy coding!
European Best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.
