How do you run background work in ASP.NET Core?
Quick Answer
Implement IHostedService, or more commonly inherit BackgroundService and override ExecuteAsync(CancellationToken stoppingToken). Register with AddHostedService<T>(). The host starts it on boot and signals the stoppingToken on shutdown so you can finish gracefully.
The building block is BackgroundService, which is a base class over IHostedService. You override ExecuteAsync, which gets a stoppingToken that trips on shutdown, and you register it with AddHostedService. Two gotchas: it's a singleton, so if I need a DbContext I create a DI scope inside each loop iteration; and for work that's triggered by an HTTP request but shouldn't block the response, I push a message onto an in-memory Channel and have the background service drain it. If the work has to survive a crash or run across instances, I don't hand-roll it — I use Hangfire or a proper message queue.
- Hosted services are singletons — to use a scoped service (like
DbContext) create a scope per iteration:using var scope = _scopeFactory.CreateScope();. - For fire-and-forget work triggered by requests, use a queue: a singleton
Channel<T>producer + aBackgroundServiceconsumer. - Don't block
StartAsyncwith long work — kick it off and return. - For anything needing durability, retries, or multi-instance coordination, use a real queue/scheduler (Hangfire, Quartz, a message broker) instead.