C# Academy · Oppitunti

IHostedService ja BackgroundService

Toteuttakaa IHostedService ja abstrakti BackgroundService suorittaaksenne taustatyötä .NET-isännän sisällä.

Oppitunti 1/412 vaihetta

IHostedService ja BackgroundService on ilmainen C# Academy-oppitunti CoddyKitissä. Tämä on oppitunti 1/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu C# Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. C# Academy-kurssilla on yhteensä 4 oppituntia.

Mitä taustapalvelut ovat?

Taustapalvelut suorittavat pitkäkestoisia tehtäviä ASP.NET Core -sovelluksen rinnalla — ne voivat käsitellä jonoja, suorittaa ajastettuja tehtäviä tai valvoa resursseja. .NET tarjoaa kaksi vaihtoehtoa: IHostedService (minimaalinen) ja abstraktin BackgroundService-luokan (silmukoille sopiva).

IHostedService-rajapinta

IHostedService-rajapinnassa on kaksi metodia: StartAsync (kutsutaan hostin käynnistyessä) ja StopAsync (kutsutaan hallitun sammutuksen aikana). Se sopii erinomaisesti kertaluonteisiin käynnistys- ja sammutustehtäviin.

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: pitkäkestoiset silmukat

BackgroundService on abstrakti luokka, joka toteuttaa IHostedService-rajapinnan ja tarjoaa metodin ExecuteAsync(CancellationToken) — se suoritetaan sovelluksen koko elinkaaren ajan.

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

Scoped-palveluiden käyttäminen

Taustapalvelut ovat Singleton-palveluita. Jos haluatte käyttää Scoped-palveluita, kuten DbContext-oliota, luokaa aina uusi scope jokaista työyksikköä varten IServiceScopeFactory-tehtaan avulla.

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

Hallittu sammutus

Kun host sammutetaan, se laukaisee peruutustunnisteen. ExecuteAsync-metodin tulee tarkkailla sitä ja suorittaa siivous. Host odottaa oletusarvoisesti enintään 5 sekuntia ennen pakotettua sammutusta.

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

Channel-pohjainen taustajono

Yleinen toimintamalli on, että taustapalvelu lukee tehtäviä Channel-jonosta samalla, kun HTTP-päätepisteet lisäävät siihen työyksiköitä. Näin pyyntöjen käsittely erotetaan työn suorittamisesta.

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

Taustapalveluiden virheenkäsittely

ExecuteAsync-metodin käsittelemättömät poikkeukset voivat pysäyttää palvelun huomaamatta. Ympäröikää pääsilmukka try/catch-rakenteella ja kirjatkaa virheet lokiin, jotta palvelu pysyy käynnissä yksittäisistä virheistä huolimatta.

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 ja sammutuksen aikakatkaisu

Ohittakaa StopAsync siivouksen suorittamista varten. Host välittää sammutustunnisteen — jos siivous kestää aikakatkaisua pidempään, prosessi lopetetaan joka tapauksessa.

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

Useita taustapalveluita

Rekisteröikää useita hosted-palveluita — ne kaikki suoritetaan samanaikaisesti. Host käynnistää ne järjestyksessä ja pysäyttää ne käänteisessä järjestyksessä.

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

Käytännön esimerkki: tilausten käsittelijä

Taustapalvelu, joka käsittelee tietokantajonossa olevat tilaukset asianmukaisesti rajattuna ja virheet käsitellen.

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

Pikatarkistus

Miksi taustapalveluiden on käytettävä IServiceScopeFactorya sen sijaan, että DbContext injektoitaisiin suoraan?

Kertaus: IHostedService ja BackgroundService

Keskeiset opit:

  • IHostedService: StartAsync/StopAsync — käynnistys- ja sammutustehtäviin
  • BackgroundService: ExecuteAsync-silmukka — jatkuvaan taustatyöhön
  • Käyttäkää aina IServiceScopeFactory-tehdasta Scoped-riippuvuuksiin taustapalveluiden sisällä
  • Tarkkailkaa peruutustunnistetta jokaisessa await-kutsussa hallitun sammutuksen varmistamiseksi
  • Ympäröikää silmukan runko try/catch-rakenteella, jotta virheet eivät pysäytä palvelua
  • Käyttäkää HostOptions.ShutdownTimeout-asetusta, jos siivous kestää yli 5 sekuntia
Aloita maksutta

Opi C# tekoälytuutorin avulla — ilmaiseksi

Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.

Kurssit
93
Oppitunnit
346

Usein kysytyt kysymykset

Onko oppitunti ”IHostedService ja BackgroundService” ilmainen?

Kyllä – oppitunnin ”IHostedService ja BackgroundService” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko C# Academy-kurssin, päivitä CoddyKit PROhon. C# Academy-kurssilla on yhteensä 4 oppituntia.

Mitä opin oppitunnilla ”IHostedService ja BackgroundService”?

Toteuttakaa IHostedService ja abstrakti BackgroundService suorittaaksenne taustatyötä .NET-isännän sisällä. Harjoittelet C# Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.

Tarvitsenko kokemusta aloittaakseni C# Academy-opiskelun?

Aiempi kokemus ei ole tarpeen. CoddyKitin C# Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 1/4.

Kuinka kauan ”IHostedService ja BackgroundService”-oppitunnin suorittaminen kestää?

Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.

Voinko kirjoittaa ja suorittaa koodia tällä C# Academy-oppitunnilla?

Kyllä. Jokainen C# Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.

Kaikki tämän kurssin oppitunnit

  1. IHostedService ja BackgroundService
  2. Worker Service -projektit
  3. Toistuvat tehtävät ja ajastimet
  4. Quartz.NET-ajastetut työt
← Takaisin: C# Academy