C# Academy · leksjon

IHostedService og BackgroundService

Implementer IHostedService og den abstrakte BackgroundService for å kjøre arbeid i bakgrunnen i en .NET-host.

Leksjon 1 av 412 trinn

IHostedService og BackgroundService er en gratis leksjon i C# Academy på CoddyKit. Dette er leksjon 1 av 4. Du kan lese hele leksjonen gratis nedenfor – og deretter øve praktisk i nettleseren med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i C# Academy, og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i C# Academy inneholder totalt 4 leksjoner.

Hva er bakgrunnstjenester?

Bakgrunnstjenester utfører langvarige oppgaver parallelt med ASP.NET Core-appen — for eksempel behandling av køer, kjøring av planlagte oppgaver eller overvåking av ressurser. .NET tilbyr to alternativer: IHostedService (minimal) og den abstrakte BackgroundService (egnet for løkker).

Grensesnittet IHostedService

IHostedService har to metoder: StartAsync (kalles når verten starter) og StopAsync (kalles under kontrollert avslutning). Det egner seg godt for engangsoppgaver ved oppstart og avslutning.

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 som implementerer IHostedService og tilbyr ExecuteAsync(CancellationToken) — en metode som kjører så lenge appen kjører.

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>();

Bruk av Scoped-tjenester

Bakgrunnstjenester er Singletoner. For å bruke Scoped-tjenester (for eksempel DbContext) må De alltid opprette et nytt scope per arbeidsenhet ved hjelp av 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);
        }
    }
}

Kontrollert avslutning

Når verten avsluttes, utløser den cancellation tokenen. ExecuteAsync skal følge med på den og rydde opp. Verten venter som standard i opptil 5 sekunder før den tvinger frem en avslutning.

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();
    }
}

Kø for bakgrunnsarbeid basert på Channel

Et vanlig mønster er at en bakgrunnstjeneste leser fra en Channel-kø, mens HTTP-endepunkter legger arbeidsenheter i kø. Dette kobler forespørselshåndtering fra behandlingen av arbeidet.

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>();

Feilhåndtering i bakgrunnstjenester

Uhåndterte unntak i ExecuteAsync kan stoppe tjenesten uten synlig varsel. Omslutt hovedløkken med try/catch og logg feilene, slik at tjenesten fortsetter å kjøre selv om enkeltoperasjoner mislykkes.

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 tidsavbrudd ved avslutning

Overstyr StopAsync for å utføre opprydding. Verten sender et avslutningssignal — hvis oppryddingen tar lengre tid enn tidsavbruddet, avsluttes prosessen med tvang uansett.

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 bakgrunnstjenester

Registrer flere hostede tjenester — de kjører alle samtidig. Verten starter dem i rekkefølge og stopper dem i omvendt rekkefø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 shutdown

Fra virkeligheten: Arbeider for ordrebehandling

En bakgrunnstjeneste som behandler ventende ordrer fra en databasekø, med korrekt scope-håndtering og feilhåndtering.

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);
        }
    }
}

Kort sjekk

Hvorfor må bakgrunnstjenester bruke IServiceScopeFactory i stedet for å injisere DbContext direkte?

Oppsummering: IHostedService og BackgroundService

Viktige punkter:

  • IHostedService: StartAsync/StopAsync — for oppgaver ved oppstart og avslutning
  • BackgroundService: ExecuteAsync-løkke — for kontinuerlig bakgrunnsarbeid
  • Bruk alltid IServiceScopeFactory for Scoped-avhengigheter i bakgrunnstjenester
  • Følg med på cancellation token ved hver await for å oppnå en kontrollert avslutning
  • Omslutt løkkens innhold med try/catch for å hindre at tjenesten stopper ved feil
  • Bruk HostOptions.ShutdownTimeout hvis oppryddingen trenger mer enn 5 sekunder
Gratis å komme i gang

Lær deg C# med en AI-veileder – gratis

Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.

Kurs
93
Leksjoner
346

Ofte stilte spørsmål

Er leksjonen «IHostedService og BackgroundService» gratis?

Ja – hele teksten i «IHostedService og BackgroundService» er gratis å lese her på nettet. For å øve interaktivt med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt, og for å låse opp resten av C# Academy-kurset, kan du oppgradere til CoddyKit PRO. Kurset i C# Academy inneholder totalt 4 leksjoner.

Hva lærer jeg i «IHostedService og BackgroundService»?

Implementer IHostedService og den abstrakte BackgroundService for å kjøre arbeid i bakgrunnen i en .NET-host. Du øver på C# Academy med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.

Trenger jeg erfaring for å begynne med C# Academy?

Ingen tidligere erfaring er nødvendig. C# Academy på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 1 av 4.

Hvor lang tid tar leksjonen «IHostedService og BackgroundService»?

De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.

Kan jeg skrive og kjøre kode i denne C# Academy-leksjonen?

Ja. Alle C# Academy-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.

Alle leksjonene i dette kurset

  1. IHostedService og BackgroundService
  2. Worker Service-prosjekter
  3. Periodiske oppgaver og tidsur
  4. Planlagte jobber med Quartz.NET
← Tilbake til C# Academy