Workerdienste in .NET
Es gibt zahlreiche Gründe für die Erstellung von Diensten mit langer Laufzeit, z. B.:
- Verarbeiten CPU-intensiver Daten.
- Queuing von Arbeitselementen im Hintergrund.
- Ausführen eines zeitbasierten Vorgangs nach einem Zeitplan.
Die Verarbeitung von Hintergrunddiensten umfasst in der Regel keine Benutzeroberfläche, aber Benutzeroberflächen können um sie herum erstellt werden. Aus diesen Gründen konnten Windows-Entwickler in den Anfängen von .NET Framework Windows-Dienste erstellen. Nun können Sie mit .NET den BackgroundService, eine Implementierung von IHostedService, verwenden oder ihren eigenen implementieren.
Mit .NET sind Sie nicht mehr auf Windows beschränkt. Sie können plattformübergreifende Hintergrunddienste entwickeln. Gehostete Dienste sind protokollierungs-, konfigurations- und Dependency Injection(DI)-bereit. Sie sind Teil der Erweiterungssammlung von Bibliotheken, was bedeutet, dass sie für alle .NET-Workloads, die mit dem generischen Host arbeiten, von grundlegender Bedeutung sind.
Wichtig
Bei der Installation des .NET SDK werden auch Microsoft.NET.Sdk.Worker
und die Workervorlage installiert. Anders ausgedrückt: Nach der Installation des .NET SDK können Sie mithilfe des Befehls dotnet new worker einen neuen Worker erstellen. Wenn Sie Visual Studio verwenden, wird die Vorlage ausgeblendet, bis die optionale ASP.NET- und Webentwicklungsworkload installiert ist.
Begriff
Viele Begriffe werden fälschlicherweise synonym verwendet. In diesem Abschnitt werden einige dieser Begriffe definiert, um ihre Absicht in diesem Artikel deutlicher zu machen.
- Hintergrunddienst: Der BackgroundService-Typ
- Gehosteter Dienst: Implementierungen von IHostedService, oder der IHostedService selbst
- Dienst mit langer Ausführungszeit: Jeder Dienst, der kontinuierlich ausgeführt wird.
- Windows-Dienst: Die Infrastruktur des Windows-Diensts, die ursprünglich .NET Framework-zentrisch war, aber jetzt über .NET zugänglich ist
- Workerdienst: Die Workerdienstvorlage
Workerdienstvorlage
Die Workerdienstvorlage ist für die .NET CLI und Visual Studio verfügbar. Weitere Informationen finden Sie unter .NET CLI, dotnet new worker
: Vorlage. Die Vorlage besteht aus einer Program
- und einer Worker
-Klasse.
using App.WorkerService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();
IHost host = builder.Build();
host.Run();
Die vorangehende Program
-Klasse:
- Erstellt eine HostApplicationBuilder.
- Ruft AddHostedService auf, um
Worker
als gehosteten Dienst zu registrieren. - Erstellt einen IHost über den Generator.
- Ruft
Run
für diehost
-Instanz auf, die die App ausführt.
Vorlagenstandards
Die Worker-Vorlage aktiviert standardmäßig keine Server Garbage Collection (GC), da es zahlreiche Faktoren gibt, die bei der Bestimmung ihrer Notwendigkeit eine Rolle spielen. In allen Szenarien, in denen Dienste mit langer Ausführungszeit erforderlich sind, sollten die Auswirkungen dieser Standardeinstellung auf die Leistung berücksichtigt werden. Um die Server-GC zu aktivieren, fügen Sie der Projektdatei den Knoten ServerGarbageCollection
hinzu:
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>
Nachteile und Überlegungen
Aktiviert | Disabled |
---|---|
Effiziente Speicherverwaltung: Übernimmt automatisch nicht genutzten Speicher, um Speicherverluste zu verhindern und die Ressourcennutzung zu optimieren. | Verbesserte Echtzeitleistung: Verhindert potenzielle Pausen oder Unterbrechungen, die durch die Garbage Collection in latenzempfindlichen Anwendungen verursacht werden. |
Langfristige Stabilität: Hilft Standard stabile Leistung in langfristigen Diensten zu gewährleisten, indem der Speicher über längere Zeiträume verwaltet wird. | Ressourceneffizienz: Kann CPU- und Arbeitsspeicherressourcen in ressourcengeschränkten Umgebungen sparen. |
Reduzierte Wartung: Minimiert den Bedarf an manueller Speicherverwaltung und vereinfacht die Wartung. | Manuelle Speichersteuerung: Bietet eine differenzierte Kontrolle über den Speicher für spezialisierte Anwendungen. |
Vorhersehbares Verhalten: Trägt zu konsistentem und vorhersagbarem Anwendungsverhalten bei. | Geeignet für kurzlebige Prozesse: Minimiert den Aufwand der Garbage Collection für kurzlebige oder kurzlebige Prozesse. |
Weitere Informationen zu Leistungsüberlegungen finden Sie unter Server-GC. Weitere Informationen zum Konfigurieren der Server-GC finden Sie unter Beispiele für die Konfiguration der Server-GC.
Worker-Klasse
Für den Worker
bietet die Vorlage eine einfache Implementierung.
namespace App.WorkerService;
public sealed class Worker(ILogger<Worker> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
await Task.Delay(1_000, stoppingToken);
}
}
}
Die vorangehende Worker
-Klasse ist eine Unterklasse von BackgroundService, die IHostedService implementiert. Der BackgroundService ist ein abstract class
und erfordert die Unterklasse, um BackgroundService.ExecuteAsync(CancellationToken) zu implementieren. In der Vorlagenimplementierung wird ein Mal pro Sekunde eine ExecuteAsync
-Schleife erstellt, und das aktuelle Datum und die aktuelle Uhrzeit werden protokolliert, bis der Prozess abgebrochen wird.
Die Projektdatei.
Die Workervorlage basiert auf der folgenden Sdk
-Projektdatei:
<Project Sdk="Microsoft.NET.Sdk.Worker">
Weitere Informationen finden Sie unter .NET-Projekt-SDKs.
NuGet-Paket
Eine App, die auf der Workervorlage basiert, verwendet das Microsoft.NET.Sdk.Worker
SDK und verfügt über einen expliziten Paketverweis auf das Microsoft.Extensions.Hosting-Paket.
Container und Cloudanpassungsfähigkeit
Bei den meisten modernen .NET-Workloads sind Container eine praktikable Option. Wenn Sie über die Workervorlage in Visual Studio einen Dienst mit langer Ausführungszeit erstellen, können Sie Docker-Unterstützung verwenden. Dadurch wird eine Dockerfile-Datei erstellt, die Ihre .NET-App containerisiert. Eine Dockerfile-Datei ist eine Reihe von Anweisungen zum Erstellen eines Images. Bei .NET-Apps befindet sich die Dockerfile-Datei in der Regel im Stamm des Verzeichnisses neben einer Projektmappendatei.
# See https://aka.ms/containerfastmode to understand how Visual Studio uses this
# Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/runtime:8.0@sha256:e6b552fd7a0302e4db30661b16537f7efcdc0b67790a47dbf67a5e798582d3a5 AS base
WORKDIR /app
FROM mcr.microsoft.com/dotnet/sdk:8.0@sha256:35792ea4ad1db051981f62b313f1be3b46b1f45cadbaa3c288cd0d3056eefb83 AS build
WORKDIR /src
COPY ["background-service/App.WorkerService.csproj", "background-service/"]
RUN dotnet restore "background-service/App.WorkerService.csproj"
COPY . .
WORKDIR "/src/background-service"
RUN dotnet build "App.WorkerService.csproj" -c Release -o /app/build
FROM build AS publish
RUN dotnet publish "App.WorkerService.csproj" -c Release -o /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "App.WorkerService.dll"]
Die obigen Dockerfile-Schritte umfassen Folgendes:
- Festlegen des Basisimages von
mcr.microsoft.com/dotnet/runtime:8.0
als Aliasbase
. - Ändern des Arbeitsverzeichnisses in /app.
- Festlegen des
build
-Alias aus dem Imagemcr.microsoft.com/dotnet/sdk:8.0
. - Ändern des Arbeitsverzeichnisses in /src.
- Kopieren des Inhalts und Veröffentlichen der .NET-App:
- Die App wird mit dem Befehl
dotnet publish
veröffentlicht.
- Die App wird mit dem Befehl
- Neuschichten des .NET SDK-Image aus
mcr.microsoft.com/dotnet/runtime:8.0
(base
-Alias). - Kopieren der veröffentlichten Buildausgabe aus /publish.
- Definieren des Einstiegspunkts, der an
dotnet App.BackgroundService.dll
delegiert wird.
Tipp
MCR in mcr.microsoft.com
steht für „Microsoft Container Registry“ und ist der syndizierte Containerkatalog von Microsoft aus dem offiziellen Docker-Hub. Der Artikel Microsoft syndicates container catalog enthält zusätzliche Details.
Wenn Sie Docker als Bereitstellungsstrategie für Ihren .NET-Workerdienst verwenden, sind in der Projektdatei einige Aspekte zu berücksichtigen:
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<RootNamespace>App.WorkerService</RootNamespace>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.0" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
</ItemGroup>
</Project>
In der obigen Projektdatei gibt das <DockerDefaultTargetOS>
-Element Linux
als Ziel an. Sollen Windows-Container das Ziel sein, verwenden Sie stattdessen Windows
. Das Microsoft.VisualStudio.Azure.Containers.Tools.Targets
NuGet-Paket wird automatisch als Paketverweis hinzugefügt, wenn Docker-Unterstützung aus der Vorlage ausgewählt wird.
Weitere Informationen zu Docker mit .NET finden Sie unter Tutorial: Containerisieren einer .NET-App. Weitere Informationen zur Bereitstellung in Azure finden Sie unter Tutorial: Bereitstellen eines Workerdiensts in Azure.
Wichtig
Wenn Sie Benutzergeheimnisse mit der Workervorlage nutzen möchten, müssen Sie explizit auf das NuGet-Paket Microsoft.Extensions.Configuration.UserSecrets
verweisen.
Erweiterbarkeit gehosteter Dienste
In der IHostedService-Schnittstelle sind zwei Methoden definiert:
Diese beiden Methoden dienen als Lebenszyklusmethoden – sie werden jeweils beim Starten und Beenden des Hosts aufgerufen.
Hinweis
Wenn die StartAsync- oder StopAsync-Methoden außer Kraft gesetzt werden, müssen Sie die base
-Klassenmethode aufrufen und await
verwenden, um sicherzustellen, dass der Dienst ordnungsgemäß gestartet und/oder beendet wird.
Wichtig
Die Schnittstelle dient als generische Parametereinschränkung für die Erweiterungsmethode AddHostedService<THostedService>(IServiceCollection), was bedeutet, dass nur Implementierungen zulässig sind. Sie können den bereitgestellten BackgroundService mit einer Unterklasse verwenden oder gänzlich ihren eigenen implementieren.
Signalisieren des Abschlusses
In den meisten gängigen Szenarien müssen Sie den Abschluss eines gehosteten Diensts nicht explizit signalisieren. Wenn der Host die Dienste startet, werden sie per Design so lange ausgeführt, bis der Host beendet wird. In einigen Szenarien müssen Sie jedoch möglicherweise den Abschluss der gesamten Hostanwendung signalisieren, wenn der Dienst abgeschlossen ist. Um den Abschluss zu signalisieren, ziehen Sie die folgende Worker
-Klasse in Betracht:
namespace App.SignalCompletionService;
public sealed class Worker(
IHostApplicationLifetime hostApplicationLifetime,
ILogger<Worker> logger) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// TODO: implement single execution logic here.
logger.LogInformation(
"Worker running at: {Time}", DateTimeOffset.Now);
await Task.Delay(1_000, stoppingToken);
// When completed, the entire app host will stop.
hostApplicationLifetime.StopApplication();
}
}
Im vorherigen Code wird die ExecuteAsync
-Methode nicht in einer Schleife ausgeführt. Wenn sie abgeschlossen ist, ruft sie IHostApplicationLifetime.StopApplication() auf.
Wichtig
Dadurch wird dem Host signalisiert, dass er beendet werden soll, und ohne den Aufruf StopApplication
wird der Host auf unbestimmte Zeit weiter ausgeführt.
Weitere Informationen finden Sie unter
- Generischer .NET-Host: IHostApplicationLifetime
- Generischer .NET-Host: Host herunterfahren
- Generischer .NET-Host: Prozess zum Herunterfahren des Hostings
Siehe auch
- BackgroundService Tutorials zu Unterklassen:
- Benutzerdefinierte IHostedService-Implementierung: