IHostedService og BackgroundService
Implementér IHostedService og den abstrakte BackgroundService for at køre arbejde i baggrunden i en .NET-host.
IHostedService og BackgroundService er en gratis C# Academy-lektion på CoddyKit. Dette er lektion 1 af 4. Du kan læse hele lektionen gratis nedenfor — og derefter øve dig praktisk i browseren med en indbygget kodeeditor og en AI-vejleder, der er tilgængelig døgnet rundt. Den er en del af læringsforløbet i C# Academy, og dine fremskridt synkroniseres på tværs af nettet og CoddyKit-appen. C# Academy-kurset indeholder 4 lektioner i alt.
Hvad er baggrundstjenester?
Baggrundstjenester udfører langvarigt arbejde parallelt med din ASP.NET Core-app — de behandler køer, kører planlagte opgaver eller overvåger ressourcer. .NET indeholder to grænseflader: IHostedService (minimal) og den abstrakte BackgroundService (velegnet til løkker).
Grænsefladen IHostedService
IHostedService har to metoder: StartAsync (kaldes, når værten starter) og StopAsync (kaldes under kontrolleret nedlukning). Den er ideel til engangsopgaver ved opstart og nedlukning.
public class DatabaseMigratorService : IHostedService
{
private readonly IServiceScopeFactory _scopeFactory;
public DatabaseMigratorService(IServiceScopeFactory sf) => _scopeFactory = sf;
public async Task StartAsync(CancellationToken ct)
{
using var scope = _scopeFactory.CreateScope();
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await db.Database.MigrateAsync(ct);
}
public Task StopAsync(CancellationToken ct) => Task.CompletedTask;
}
builder.Services.AddHostedService<DatabaseMigratorService>();BackgroundService: Langvarige løkker
BackgroundService er en abstrakt klasse, der implementerer IHostedService og leverer ExecuteAsync(CancellationToken) — en metode, der kører i hele appens levetid.
public class HeartbeatService : BackgroundService
{
private readonly ILogger<HeartbeatService> _logger;
public HeartbeatService(ILogger<HeartbeatService> l) => _logger = l;
protected override async Task ExecuteAsync(CancellationToken ct)
{
_logger.LogInformation("Heartbeat service started");
while (!ct.IsCancellationRequested)
{
_logger.LogInformation("Heartbeat: {Time}", DateTime.UtcNow);
await Task.Delay(TimeSpan.FromSeconds(30), ct);
}
_logger.LogInformation("Heartbeat service stopping");
}
}
builder.Services.AddHostedService<HeartbeatService>();Brug af tjenester med afgrænset levetid
Baggrundstjenester er singletoner. Hvis du vil bruge tjenester med afgrænset levetid (f.eks. DbContext), skal du altid oprette et nyt tjenesteområde for hver arbejdsenhed ved hjælp af IServiceScopeFactory.
public class DataSyncService : BackgroundService
{
private readonly IServiceScopeFactory _factory;
private readonly ILogger<DataSyncService> _log;
public DataSyncService(IServiceScopeFactory f, ILogger<DataSyncService> l)
{ _factory = f; _log = l; }
protected override async Task ExecuteAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
using (var scope = _factory.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await SyncDataAsync(db, ct);
} // scope and DbContext disposed here
await Task.Delay(TimeSpan.FromMinutes(5), ct);
}
}
}Kontrolleret nedlukning
Når værten lukker ned, aktiverer den annullerings-tokenet. Din ExecuteAsync bør reagere på det og rydde op. Værten venter som standard op til 5 sekunder, før den stopper processen med tvang.
protected override async Task ExecuteAsync(CancellationToken ct)
{
try
{
while (!ct.IsCancellationRequested)
{
await DoWorkAsync(ct);
await Task.Delay(1000, ct);
}
}
catch (OperationCanceledException)
{
// Normal shutdown — not an error
_logger.LogInformation("Service stopping due to cancellation");
}
finally
{
// Cleanup
await CleanupAsync();
}
}Kanalbaseret baggrundskø
Et almindeligt mønster er, at en baggrundstjeneste læser fra en Channel-kø, mens HTTP-endepunkter lægger arbejdselementer i køen. Det adskiller håndteringen af anmodninger fra behandlingen af arbejdet.
public class BackgroundTaskQueue
{
private readonly Channel<Func<CancellationToken, Task>> _queue
= Channel.CreateBounded<Func<CancellationToken, Task>>(100);
public ValueTask QueueAsync(Func<CancellationToken, Task> job)
=> _queue.Writer.WriteAsync(job);
public IAsyncEnumerable<Func<CancellationToken, Task>> DequeueAllAsync(
CancellationToken ct)
=> _queue.Reader.ReadAllAsync(ct);
}
// Register and use:
builder.Services.AddSingleton<BackgroundTaskQueue>();
builder.Services.AddHostedService<QueueProcessorService>();Fejlhåndtering i baggrundstjenester
Uhåndterede undtagelser i ExecuteAsync kan stoppe tjenesten uden varsel. Omgiv hovedløkken med try/catch, og log fejl, så tjenesten forbliver aktiv trods enkelte fejl.
protected override async Task ExecuteAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
try
{
await ProcessNextBatchAsync(ct);
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
break; // normal shutdown
}
catch (Exception ex)
{
_logger.LogError(ex, "Background processing error. Retrying in 5s.");
await Task.Delay(5000, ct); // backoff before retry
}
}
}StopAsync og tidsgrænse for nedlukning
Overskriv StopAsync for at udføre oprydning. Værten sender et nedlukningstoken — hvis oprydningen tager længere end tidsgrænsen, afsluttes processen under alle omstændigheder.
public override async Task StopAsync(CancellationToken stoppingToken)
{
_logger.LogInformation("Service is stopping...");
// Signal internal work to stop
_internalCts.Cancel();
// Wait for the Execute loop to complete (up to timeout)
await base.StopAsync(stoppingToken);
_logger.LogInformation("Service stopped");
}
// Increase the shutdown timeout if needed:
builder.Services.Configure<HostOptions>(opt =>
opt.ShutdownTimeout = TimeSpan.FromSeconds(30));Flere baggrundstjenester
Registrér flere værtsbaserede tjenester — de kører alle samtidig. Værten starter dem i rækkefølge og stopper dem i omvendt rækkefølge.
builder.Services.AddHostedService<DatabaseMigratorService>(); // startup task
builder.Services.AddHostedService<MetricsCollectorService>(); // continuous
builder.Services.AddHostedService<EmailNotificationService>(); // continuous
builder.Services.AddHostedService<CacheWarmupService>(); // startup task
// All run concurrently after app start
// Stopped in reverse registration order on shutdownPraktisk eksempel: baggrundsarbejder til ordrebehandling
En baggrundstjeneste, der behandler ventende ordrer fra en databasekø med korrekt håndtering af tjenesteområder og fejl.
public class OrderProcessorService : BackgroundService
{
private readonly IServiceScopeFactory _factory;
private readonly ILogger<OrderProcessorService> _log;
public OrderProcessorService(IServiceScopeFactory f, ILogger<OrderProcessorService> l)
{ _factory = f; _log = l; }
protected override async Task ExecuteAsync(CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
try
{
using var scope = _factory.CreateScope();
var processor = scope.ServiceProvider.GetRequiredService<IOrderProcessor>();
int count = await processor.ProcessPendingAsync(ct);
_log.LogInformation("Processed {Count} orders", count);
}
catch (Exception ex) when (!ct.IsCancellationRequested)
{
_log.LogError(ex, "Order processing failed");
}
await Task.Delay(TimeSpan.FromSeconds(10), ct);
}
}
}Hurtigt tjek
Hvorfor skal baggrundstjenester bruge IServiceScopeFactory i stedet for at få DbContext injiceret direkte?
Opsummering: IHostedService og BackgroundService
Vigtigste pointer:
IHostedService: StartAsync/StopAsync — til opgaver ved opstart og nedlukningBackgroundService: ExecuteAsync-løkke — til kontinuerligt baggrundsarbejde- Brug altid
IServiceScopeFactorytil afhængigheder med afgrænset levetid i baggrundstjenester - Kontrollér annullerings-tokenet ved hvert await for at opnå en kontrolleret nedlukning
- Omgiv løkkens krop med try/catch for at forhindre, at tjenesten dør på grund af fejl
- Brug
HostOptions.ShutdownTimeout, hvis oprydningen kræver mere end 5 sekunder
Lær C# med en AI-underviser — gratis
Skriv og kør rigtig kode i din browser, få øjeblikkelig hjælp fra en AI-underviser døgnet rundt, og fortsæt, hvor du slap, på web eller i appen.
- Kurser
- 93
- Lektioner
- 346
Ofte stillede spørgsmål
Er lektionen “IHostedService og BackgroundService” gratis?
Ja — hele teksten til “IHostedService og BackgroundService” kan læses gratis her på nettet. Hvis du vil øve dig interaktivt med en indbygget kodeeditor og en AI-vejleder døgnet rundt og få adgang til resten af C# Academy-kurset, skal du opgradere til CoddyKit PRO. C# Academy-kurset indeholder 4 lektioner i alt.
Hvad lærer jeg i “IHostedService og BackgroundService”?
Implementér IHostedService og den abstrakte BackgroundService for at køre arbejde i baggrunden i en .NET-host. Du øver dig i C# Academy med praktisk kode, som du kører direkte i browseren, og en AI-vejleder døgnet rundt besvarer dine spørgsmål, mens du arbejder dig gennem lektionen.
Skal jeg have erfaring for at begynde på C# Academy?
Der kræves ingen tidligere erfaring. C# Academy på CoddyKit er tilrettelagt for både begyndere og øvede, så du kan starte her eller fra begyndelsen og lære i dit eget tempo. Dette er lektion 1 af 4.
Hvor lang tid tager lektionen “IHostedService og BackgroundService”?
De fleste CoddyKit-lektioner tager cirka 5–10 minutter. Hver lektion er kort og interaktiv, så du gør løbende fremskridt og kan fortsætte, hvor du slap – på både web og app.
Kan jeg skrive og køre kode i denne C# Academy-lektion?
Ja. Alle C# Academy-lektioner har en indbygget kodeeditor, så du kan skrive og køre rigtig kode direkte i din browser og få øjeblikkelig feedback fra AI – uden lokal opsætning.
Alle lektioner i dette kursus
- IHostedService og BackgroundService
- Worker Service-projekter
- Periodiske opgaver og timere
- Planlagte Quartz.NET-jobs