Verwenden bereichsbezogener Dienste in einem BackgroundService
Wenn Sie Implementierungen von IHostedService mit einer der AddHostedService-Erweiterungsmethoden registrieren, wird der Dienst als Singleton registriert. Es kann Szenarien geben, in denen Sie einen bereichsbezogenen Dienst benötigen. Weitere Informationen finden Sie unter Abhängigkeitsinjektion in .NET: Dienstlebensdauer.
In diesem Tutorial lernen Sie Folgendes:
- Auflösen bereichsbezogener Abhängigkeiten in BackgroundService als Singleton
- Delegieren von Aufgaben an einen bereichsbezogenen Dienst
- Implementieren von
override
für BackgroundService.StopAsync(CancellationToken)
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 bereichsbezogener Dienste
Erstellen Sie einen Bereich, um bereichsbezogene Dienste in einem BackgroundService
zu verwenden. Bereiche werden für einen gehosteten Dienst nicht standardmäßig erstellt. Der bereichsbezogene Hintergrunddienst enthält die Logik der Hintergrundaufgabe.
namespace App.ScopedService;
public interface IScopedProcessingService
{
Task DoWorkAsync(CancellationToken stoppingToken);
}
Die vorangehende Schnittstelle definiert eine einzelne DoWorkAsync
-Methode. So legen Sie die Standardimplementierung fest
- Der Dienst ist asynchron. Die
DoWorkAsync
-Methode gibtTask
zurück. Zu Demonstrationszwecken wird in derDoWorkAsync
-Methode eine Verzögerung von zehn Sekunden verwendet. - Ein ILogger wird in den Dienst eingefügt:
namespace App.ScopedService;
public sealed class DefaultScopedProcessingService(
ILogger<DefaultScopedProcessingService> logger) : IScopedProcessingService
{
private int _executionCount;
public async Task DoWorkAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
++ _executionCount;
logger.LogInformation(
"{ServiceName} working, execution count: {Count}",
nameof(DefaultScopedProcessingService),
_executionCount);
await Task.Delay(10_000, stoppingToken);
}
}
}
Der gehostete Dienst erstellt einen Bereich, um den bereichsbezogenen Hintergrunddienst so aufzulösen, dass dessen DoWorkAsync
-Methode aufgerufen wird. DoWorkAsync
gibt einen Task
zurück, auf den in ExecuteAsync
gewartet wird:
Erneutes Generieren der Worker-Klasse
Ersetzen Sie die vorhandene Worker
-Klasse durch den folgenden C#-Code, und benennen Sie die Datei in ScopedBackgroundService.cs um:
namespace App.ScopedService;
public sealed class ScopedBackgroundService(
IServiceScopeFactory serviceScopeFactory,
ILogger<ScopedBackgroundService> logger) : BackgroundService
{
private const string ClassName = nameof(ScopedBackgroundService);
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is running.", ClassName);
await DoWorkAsync(stoppingToken);
}
private async Task DoWorkAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is working.", ClassName);
using (IServiceScope scope = serviceScopeFactory.CreateScope())
{
IScopedProcessingService scopedProcessingService =
scope.ServiceProvider.GetRequiredService<IScopedProcessingService>();
await scopedProcessingService.DoWorkAsync(stoppingToken);
}
}
public override async Task StopAsync(CancellationToken stoppingToken)
{
logger.LogInformation(
"{Name} is stopping.", ClassName);
await base.StopAsync(stoppingToken);
}
}
Im vorherigen Code wird ein expliziter Bereich erstellt und die IScopedProcessingService
-Implementierung von der Dienstumfangsfactory für die Abhängigkeitsinjektion aufgelöst. Die aufgelöste Dienstinstanz ist bereichsbezogen, und ihre DoWorkAsync
-Methode wird erwartet.
Ersetzen Sie den Inhalt der Vorlagendatei Program.cs durch den folgenden C#-Code:
using App.ScopedService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<ScopedBackgroundService>();
builder.Services.AddScoped<IScopedProcessingService, DefaultScopedProcessingService>();
IHost host = builder.Build();
host.Run();
Die Dienste werden in (Program.cs) registriert. Der gehostete Dienst wird mit der Erweiterungsmethode AddHostedService
registriert.
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.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is running.
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService is working.
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 1
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: .\scoped-service
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 2
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 3
info: App.ScopedService.DefaultScopedProcessingService[0]
DefaultScopedProcessingService working, execution count: 4
info: Microsoft.Hosting.Lifetime[0]
Application is shutting down...
info: App.ScopedService.ScopedBackgroundService[0]
ScopedBackgroundService 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.