IHostedService lets a .NET application run work in the background instead of making a user wait for it. An ASP.NET Core app can, for example, accept a request to send an email, return a response, and process the queued email separately. Hosted services start and stop with the application. section 34.1
public interface IHostedService
{
Task StartAsync(CancellationToken cancellationToken);
Task StopAsync(CancellationToken cancellationToken);
}
The interface has two lifecycle methods: StartAsync runs during application startup, and StopAsync runs as the application shuts down. section 34.1.1
StartAsync runs inline during startup. If it waits for a long-running task to finish, the application cannot finish starting. For work that should continue throughout the application’s lifetime, usually derive from BackgroundService instead. Override ExecuteAsync, do the work there, and use its CancellationToken to stop when shutdown begins. Waiting in StartAsync can still be useful when the app must complete a task before handling requests. section 34.1.1 section 34.4
Keep an exchange-rate endpoint fast
A hosted service can repeatedly fetch exchange rates from a remote API and update a shared cache. The endpoint reads the cache rather than making its own HTTP call. Register the typed client, register the cache as a singleton, and add the background task with AddHostedService<ExchangeRatesHostedService>(). If the first update must succeed before requests begin, StartAsync can deliberately wait for it. section 34.1.1
Listing 34.3 Registering an IHostedService with the DI container
WebApplicationBuilder builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpClient<ExchangeRatesClient>(); #1 builder.Services.AddSingleton<ExchangeRatesCache>(); #2 builder.Services.AddHostedService<ExchangeRatesHostedService>(); #3 #1 Registers the typed client as before #2 Adds the cache object as a singleton so it is shared throughout your app #3 Registers ExchangeRatesHostedService as an IHostedService
This registration listing shows the typed HTTP client, shared singleton cache, and hosted service added to the dependency-injection container. section 34.1.1
A hosted service is created once, so do not constructor-inject a scoped dependency into it. If each update needs a scoped service such as an EF Core DbContext, call IServiceProvider.CreateScope(), resolve the dependency from that scope, and dispose the scope when the update finishes. Unlike an HTTP request, a background task has no automatically created request scope. section 34.1.2
The same interface also supports headless worker services built with the generic IHost when no HTTP endpoint is needed. For more elaborate schedules, Quartz.NET can run its scheduler as an IHostedService; a basic hosted service need not take on that scheduling machinery. section 34.2 section 34.3
