How do you run background work in ASP.NET Core?

ASP.NET Core Hosting Intermediate 2–3 Yrs3–5 Yrs Conceptual 1 min read

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 + a BackgroundService consumer.
  • Don't block StartAsync with 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.