0Pricing
C# Academy · Lektion

IHostedService und BackgroundService

Implementieren Sie IHostedService und den abstrakten BackgroundService, um innerhalb eines .NET-Hosts Hintergrundarbeit auszuführen.

IHostedService und BackgroundService ist eine kostenlose C# Academy-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des C# Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Was sind Hintergrunddienste?

Hintergrunddienste führen neben Ihrer ASP.NET-Core-Anwendung langfristig laufende Aufgaben aus – etwa die Verarbeitung von Warteschlangen, das Ausführen geplanter Aufgaben oder die Überwachung von Ressourcen. .NET bietet zwei Schnittstellen: IHostedService (minimal) und die abstrakte Klasse BackgroundService (für Schleifen geeignet).

Die IHostedService-Schnittstelle

IHostedService verfügt über zwei Methoden: StartAsync (wird beim Start des Hosts aufgerufen) und StopAsync (wird beim ordnungsgemäßen Herunterfahren aufgerufen). Sie eignet sich ideal für einmalige Aufgaben beim Starten und Herunterfahren.

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: Lang laufende Schleifen

BackgroundService ist eine abstrakte Klasse, die IHostedService implementiert und ExecuteAsync(CancellationToken) bereitstellt – eine Methode, die während der gesamten Lebensdauer der Anwendung ausgeführt wird.

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-Dienste verwenden

Hintergrunddienste sind Singletons. Wenn Sie Scoped-Dienste (wie DbContext) verwenden möchten, erstellen Sie immer pro Arbeitseinheit mit IServiceScopeFactory einen neuen Scope.

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

Ordnungsgemäßes Herunterfahren

Beim Herunterfahren des Hosts löst dieser das CancellationToken aus. Ihr ExecuteAsync sollte es überwachen und Aufräumarbeiten durchführen. Standardmäßig wartet der Host bis zu 5 Sekunden, bevor er den Prozess zwangsweise beendet.

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

Hintergrundwarteschlange auf Channel-Basis

Ein häufig verwendetes Muster: Ein Hintergrunddienst liest aus einer Channel-Warteschlange, während HTTP-Endpunkte Arbeitselemente einreihen. Dadurch werden die Verarbeitung von Anfragen und die Ausführung der Arbeit voneinander entkoppelt.

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

Fehlerbehandlung in Hintergrunddiensten

Unbehandelte Ausnahmen in ExecuteAsync können den Dienst unbemerkt beenden. Umschließen Sie die Hauptschleife mit try/catch und protokollieren Sie Fehler, damit der Dienst trotz einzelner Fehler weiterläuft.

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 und Zeitüberschreitung beim Herunterfahren

Überschreiben Sie StopAsync, um Aufräumarbeiten durchzuführen. Der Host übergibt ein Beendigungstoken – wenn die Aufräumarbeiten länger als das Zeitlimit dauern, wird der Prozess unabhängig davon beendet.

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

Mehrere Hintergrunddienste

Registrieren Sie mehrere gehostete Dienste – sie werden alle gleichzeitig ausgeführt. Der Host startet sie in der angegebenen Reihenfolge und beendet sie in umgekehrter Reihenfolge.

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

Praxisbeispiel: Worker für die Auftragsverarbeitung

Ein Hintergrunddienst, der ausstehende Aufträge aus einer Datenbankwarteschlange verarbeitet und dabei Scopes sowie eine ordnungsgemäße Fehlerbehandlung verwendet.

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

Kurztest

Warum müssen Hintergrunddienste IServiceScopeFactory verwenden, anstatt DbContext direkt zu injizieren?

Zusammenfassung: IHostedService und BackgroundService

Wichtigste Erkenntnisse:

  • IHostedService: StartAsync/StopAsync – für Aufgaben beim Starten und Herunterfahren
  • BackgroundService: ExecuteAsync-Schleife – für kontinuierliche Hintergrundarbeiten
  • Verwenden Sie innerhalb von Hintergrunddiensten für Scoped-Abhängigkeiten immer IServiceScopeFactory
  • Überwachen Sie bei jedem await das CancellationToken, um ein ordnungsgemäßes Herunterfahren zu ermöglichen
  • Umschließen Sie den Schleifenkörper mit try/catch, damit der Dienst bei Fehlern nicht beendet wird
  • Verwenden Sie HostOptions.ShutdownTimeout, wenn die Aufräumarbeiten länger als 5 Sekunden dauern

Häufig gestellte Fragen

Ist die Lektion „IHostedService und BackgroundService“ kostenlos?

Ja — der vollständige Text von „IHostedService und BackgroundService“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des C# Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der C# Academy-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „IHostedService und BackgroundService“?

Implementieren Sie IHostedService und den abstrakten BackgroundService, um innerhalb eines .NET-Hosts Hintergrundarbeit auszuführen. Du übst C# Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um C# Academy zu starten?

Keine Vorkenntnisse erforderlich. C# Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.

Wie lange dauert die Lektion „IHostedService und BackgroundService“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser C# Academy-Lektion Code schreiben und ausführen?

Ja. Jede C# Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. IHostedService und BackgroundService
  2. Worker-Service-Projekte
  3. Periodische Aufgaben und Timer
  4. Geplante Jobs mit Quartz.NET
← Zurück zu C# Academy