Implementieren der IHostedService
-Schnittstelle
Wenn Sie begrenzte Kontrolle benötigen, die über die Bereitstellung von BackgroundService hinausgeht, können Sie einen eigenen IHostedService implementieren. Die IHostedService-Schnittstelle ist Grundlage aller zeitintensiven Dienste in .NET. Benutzerdefinierte Implementierungen werden mit der Erweiterungsmethode AddHostedService<THostedService>(IServiceCollection) registriert.
In diesem Tutorial lernen Sie Folgendes:
- Implementieren der Schnittstellen IHostedService und IAsyncDisposable
- Erstellen eines timerbasierten Diensts
- Registrieren der benutzerdefinierten Implementierung mit Abhängigkeitsinjektion und Protokollierung
Tipp
Der gesamte Quellcode des Beispiels „Worker in .NET“ steht im Beispielbrowser zum Download zur Verfügung. Weitere Informationen finden Sie unter Durchsuchen von Codebeispielen: Worker in .NET.
Voraussetzungen
- Das .NET 8.0 SDK oder höher
- In .NET integrierte Entwicklungsumgebung (Integrated Development Environment, IDE)
- Nach Wunsch Visual Studio
Erstellen eines neuen Projekts
Um ein neues Workerdienstprojekt mit Visual Studio zu erstellen, wählen Sie Datei>Neu>Projekt... aus. Suchen Sie im Dialogfeld Neues Projekt erstellen nach „Workerdienst“, und wählen Sie die Workerdienstvorlage aus. Wenn Sie lieber die .NET-CLI verwenden möchten, öffnen Sie Ihr bevorzugtes Terminal in einem Arbeitsverzeichnis. Führen Sie den Befehl dotnet new
aus, und ersetzen Sie <Project.Name>
durch den gewünschten Projektnamen.
dotnet new worker --name <Project.Name>
Weitere Informationen zum .NET-CLI-Befehl für ein neues Workerdienstprojekt finden Sie unter dotnet new worker.
Tipp
Wenn Sie Visual Studio Code verwenden, können Sie .NET CLI-Befehle über das integrierte Terminal ausführen. Weitere Informationen finden Sie unter Visual Studio Code: Integriertes Terminal.
Erstellen eines Timerdiensts
Der timerbasierte Hintergrunddienst verwendet die System.Threading.Timer-Klasse. Der Timer löst die DoWork
-Methode aus. Der Timer wird durch IHostLifetime.StopAsync(CancellationToken) deaktiviert und freigegeben, wenn der Dienstcontainer durch IAsyncDisposable.DisposeAsync() freigegeben ist:
Ersetzen Sie den Inhalt von Worker
in der Vorlage durch den folgenden C#-Code, und benennen Sie die Datei in TimerService.cs um:
namespace App.TimerHostedService;
public sealed class TimerService(ILogger<TimerService> logger) : IHostedService, IAsyncDisposable
{
private readonly Task _completedTask = Task.CompletedTask;
private int _executionCount = 0;
private Timer? _timer;
public Task StartAsync(CancellationToken stoppingToken)
{
logger.LogInformation("{Service} is running.", nameof(TimerHostedService));
_timer = new Timer(DoWork, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
return _completedTask;
}
private void DoWork(object? state)
{
int count = Interlocked.Increment(ref _executionCount);
logger.LogInformation(
"{Service} is working, execution count: {Count:#,0}",
nameof(TimerHostedService),
count);
}
public Task StopAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Service} is stopping.", nameof(TimerHostedService));
_timer?.Change(Timeout.Infinite, 0);
return _completedTask;
}
public async ValueTask DisposeAsync()
{
if (_timer is IAsyncDisposable timer)
{
await timer.DisposeAsync();
}
_timer = null;
}
}
Wichtig
Worker
ist eine Unterklasse von BackgroundService. Nun implementiert TimerService
die Schnittstellen IHostedService und IAsyncDisposable.
TimerService
ist sealed
und kaskadiert den Aufruf von DisposeAsync
von seiner _timer
-Instanz. Weitere Informationen zum „kaskadierenden Dispose-Muster“ finden Sie unter Implementieren einer DisposeAsync
-Methode.
Wenn StartAsync aufgerufen wird, wird der Timer instanziiert und anschließend gestartet.
Tipp
Timer wartet nicht auf den Abschluss vorheriger Ausführungen von DoWork
. Die veranschaulichte Vorgehensweise eignet sich also möglicherweise nicht für alle Szenarios. Interlocked.Increment wird zum Erhöhen des Ausführungszählers mit einem atomischen Vorgang verwendet, wodurch sichergestellt wird, dass _executionCount
nicht durch mehrere Threads gleichzeitig aktualisiert wird.
Ersetzen Sie den vorhandenen Inhalt von Program
durch den folgenden C#-Code:
using App.TimerHostedService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<TimerService>();
IHost host = builder.Build();
host.Run();
Der Dienst wird in (Program.cs) mit der Erweiterungsmethode AddHostedService
registriert. Dies ist die gleiche Erweiterungsmethode, die Sie beim Registrieren von Unterklassen von BackgroundService verwenden, da beide die Schnittstelle IHostedService implementieren.
Weitere Informationen zum Registrieren von Diensten finden Sie unter Abhängigkeitsinjektion in .NET.
Überprüfen der Dienstfunktionalität
Zum Ausführen der Anwendung aus Visual Studio drücken Sie F5, oder wählen Sie die Menüoption Debuggen>Debuggen starten aus. Wenn Sie die .NET-CLI verwenden, führen Sie den Befehl dotnet run
im Arbeitsverzeichnis aus:
dotnet run
Weitere Informationen zum Ausführungsbefehl in der .NET-CLI finden Sie unter dotnet run.
Lassen Sie die Anwendung eine Zeit lang laufen, um mehrere Abstufungen der Anzahl der Ausführungen zu generieren. Eine Ausgabe ähnlich der folgenden wird angezeigt:
info: App.TimerHostedService.TimerService[0]
TimerHostedService is running.
info: Microsoft.Hosting.Lifetime[0]
Application started. Press Ctrl+C to shut down.
info: Microsoft.Hosting.Lifetime[0]
Hosting environment: Development
info: Microsoft.Hosting.Lifetime[0]
Content root path: .\timer-service
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 1
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 2
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 3
info: App.TimerHostedService.TimerService[0]
TimerHostedService is working, execution count: 4
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
info: App.TimerHostedService.TimerService[0]
TimerHostedService is stopping.
Wenn Sie die Anwendung in Visual Studio ausführen, wählen Sie Debuggen>Debuggen beenden... aus. Alternativ können Sie im Konsolenfenster STRG + C drücken, um den Abbruch zu signalisieren.
Siehe auch
Es gibt mehrere damit zusammenhängende Tutorials, die Sie berücksichtigen sollten: