Section 3 of 6
Background Services
🎯 What You'll Learn
- What are background services
- IHostedService
- BackgroundService
- Scoped services
- Graceful shutdown
What are Background Services?
Background services run tasks in the background while your application is running, such as processing queues, sending emails, or cleaning up data.
IHostedService
TimedHostedService.cs
C#
public class TimedHostedService : IHostedService, IDisposable
{
private Timer _timer;
public Task StartAsync(CancellationToken cancellationToken)
{
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromMinutes(5));
return Task.CompletedTask;
}
private void DoWork(object state)
{
// Background work here
}
public Task StopAsync(CancellationToken cancellationToken)
{
_timer?.Change(Timeout.Infinite, 0);
return Task.CompletedTask;
}
public void Dispose()
{
_timer?.Dispose();
}
}
BackgroundService
Easier alternative to IHostedService.
EmailBackgroundService.cs
C#
public class EmailBackgroundService : BackgroundService
{
private readonly ILogger<EmailBackgroundService> _logger;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_logger.LogInformation("Processing email queue...");
// Process emails
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
}
}
}
Register Service
Program.cs
C#
builder.Services.AddHostedService<EmailBackgroundService>();
Using Scoped Services
With Scoped Services
C#
public class DataCleanupService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
public DataCleanupService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _serviceProvider.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<InvenTrackDbContext>();
// Clean up old data
var oldOrders = await context.Orders
.Where(o => o.CreatedAt < DateTime.UtcNow.AddYears(-1))
.ToListAsync(stoppingToken);
context.Orders.RemoveRange(oldOrders);
await context.SaveChangesAsync(stoppingToken);
}
await Task.Delay(TimeSpan.FromDays(1), stoppingToken);
}
}
}
InvenTrack Example
StockAlertService.cs
C#
public class StockAlertService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
private readonly ILogger<StockAlertService> _logger;
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
using (var scope = _serviceProvider.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<InvenTrackDbContext>();
// Find low stock products
var lowStockProducts = await context.Products
.Where(p => p.Quantity < p.ReorderLevel)
.ToListAsync(stoppingToken);
foreach (var product in lowStockProducts)
{
_logger.LogWarning("Low stock alert: {ProductName} ({Quantity} remaining)",
product.Name, product.Quantity);
// Send email notification...
}
}
// Check every hour
await Task.Delay(TimeSpan.FromHours(1), stoppingToken);
}
}
}
Key Takeaways
- Background services: Run tasks in background
- IHostedService: StartAsync/StopAsync methods
- BackgroundService: Easier with ExecuteAsync
- AddHostedService: Register service
- Scoped services: Create scope in background service
- CancellationToken: Handle graceful shutdown