Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Es gibt zahlreiche Gründe für die Erstellung langlaufender Einrichtungen, z. B.:
- Rechenintensive Daten werden verarbeitet.
- Warteschlangen von Arbeitsaufgaben im Hintergrund.
- Durchführen eines zeitbasierten Vorgangs in einem Zeitplan.
Die Verarbeitung von Hintergrunddiensten beinhaltet normalerweise keine Benutzeroberfläche (UI), aber UIs können dafür entwickelt werden. In den frühen Tagen mit .NET Framework konnten Windows-Entwickler Windows-Dienste für diese Zwecke erstellen. Jetzt können Sie mit .NET die BackgroundService verwenden, die eine Implementierung von IHostedService ist, oder Ihre eigene implementieren.
Mit .NET sind Sie nicht mehr auf Windows beschränkt. Sie können plattformübergreifende Hintergrunddienste entwickeln. Gehostete Dienste sind für Protokollierung, Konfiguration und Dependency Injection (DI) vorbereitet. Sie sind Teil der Erweiterungssuite von Bibliotheken, was bedeutet, dass sie für alle .NET-Workloads, die mit dem generischen Host arbeiten, grundlegend sind.
Von Bedeutung
Bei der Installation des .NET SDK werden auch Microsoft.NET.Sdk.Worker
und die Workervorlage installiert. Mit anderen Worten, nach der Installation des .NET SDK könnten Sie einen neuen Worker mithilfe des Befehls "dotnet new worker " erstellen. Wenn Sie Visual Studio verwenden, wird die Vorlage ausgeblendet, bis die optionale ASP.NET- und Webentwicklungsworkload installiert ist.
Terminologie
Viele Begriffe werden versehentlich 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.
- Langer Dienst: Jeder Dienst, der kontinuierlich ausgeführt wird.
- Windows-Dienst: Die Windows-Dienstinfrastruktur , ursprünglich .NET Framework-zentrierte, aber jetzt über .NET zugänglich.
- Worker Service: Die Worker Service-Vorlage .
Workerdienstvorlage
Die Worker Service-Vorlage ist in .NET CLI und Visual Studio verfügbar. Weitere Informationen finden Sie unter .NET CLI, dotnet new worker
- Template. Die Vorlage besteht aus einer Program
und 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.
- Aufrufe AddHostedService zum Registrieren des
Worker
als gehosteten Diensts. - Erstellt einen IHost vom Ersteller.
- Ruft
Run
diehost
Instanz auf, die die App ausführt.
Standardeinstellungen für Vorlagen
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. Alle Szenarien, die langlaufende Dienste erfordern, sollten die Auswirkungen auf die Leistung dieser Standardeinstellung berücksichtigen. Um die Server-GC zu aktivieren, fügen Sie den ServerGarbageCollection
Knoten zur Projektdatei hinzu:
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>
Kompromisse und Überlegungen
Aktiviert | Arbeitsunfähig |
---|---|
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: Trägt dazu bei, eine stabile Leistung in langfristigen Diensten aufrechtzuerhalten, 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 Speicherbereinigung bei kurzlebigen oder ephemeren Prozessen. |
Weitere Informationen zu Leistungsaspekten finden Sie unter Server GC. Weitere Informationen zum Konfigurieren von Server GC finden Sie in den Beispielen zur Server-GC-Konfiguration.
Arbeiterklasse
Wie bei der Worker
-Vorlage bietet diese 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 implementiert IHostedService. Dies BackgroundService ist eine abstract class
und erfordert die Implementierung BackgroundService.ExecuteAsync(CancellationToken)der Unterklasse. In der Implementierung der Vorlage wird die ExecuteAsync
-Schleife einmal pro Sekunde ausgeführt, wobei das aktuelle Datum und die aktuelle Uhrzeit protokolliert werden, bis der Prozess abgebrochen wird.
Die Projektdatei
Die Vorlage "Worker" basiert auf der folgenden Projektdatei Sdk
:
<Project Sdk="Microsoft.NET.Sdk.Worker">
Weitere Informationen finden Sie unter .NET-Projekt-SDKs.
NuGet-Paket
Eine App, die auf der Worker-Vorlage basiert, verwendet das Microsoft.NET.Sdk.Worker
SDK und verfügt über einen expliziten Paketverweis auf das Paket "Microsoft.Extensions.Hosting" .
Container und Cloud-Anpassungsfähigkeit
Bei den meisten modernen .NET-Workloads sind Container eine praktikable Option. Beim Erstellen eines lang laufenden Dienstes aus der Worker-Vorlage in Visual Studio können Sie Docker-Unterstützung einbinden. Dadurch wird eine Dockerfile erstellt, die Ihre .NET-App containerisiert. Eine Dockerfile-Datei ist eine Reihe von Anweisungen zum Erstellen eines Images. Bei .NET-Apps befindet sich dockerfile in der Regel im Stammverzeichnis neben einer Lösungsdatei.
# 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 vorherigen Dockerfile-Schritte umfassen:
- Festlegen des Basisbilds
mcr.microsoft.com/dotnet/runtime:8.0
als Aliasbase
. - Ändern des Arbeitsverzeichnisses in "/app".
- Festlegen des
build
Alias aus demmcr.microsoft.com/dotnet/sdk:8.0
Bild. - Ändern des Arbeitsverzeichnisses in "/src".
- Kopieren der Inhalte und Veröffentlichen der .NET-App:
- Die App wird mit dem
dotnet publish
Befehl veröffentlicht.
- Die App wird mit dem
- Schichten des .NET SDK-Bildes von
mcr.microsoft.com/dotnet/runtime:8.0
wiederherstellen (das Aliasbase
). - Kopieren der veröffentlichten Buildausgabe aus " /publish".
- Definieren des Einstiegspunkts, an den delegiert wird
dotnet App.BackgroundService.dll
.
Tipp
Der MCR steht in mcr.microsoft.com
für "Microsoft Container Registry" und ist Microsofts syndizierter Containerkatalog vom offiziellen Docker-Hub. Der Artikel Microsoft-Syndikate-Containerkatalog enthält zusätzliche Details.
Wenn Sie Docker als Bereitstellungsstrategie für Ihren .NET Worker Service als Ziel festlegen, gibt es einige Überlegungen in der Projektdatei:
<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.6" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.0" />
</ItemGroup>
</Project>
In der vorherigen Projektdatei gibt das <DockerDefaultTargetOS>
Element als Ziel an Linux
. Verwenden Sie stattdessen Windows
, um Windows-Container als Ziel zu verwenden. Das Microsoft.VisualStudio.Azure.Containers.Tools.Targets
NuGet-Paket wird automatisch als Paketverweis hinzugefügt, wenn die Docker-Unterstützung aus der Vorlage ausgewählt wird.
Weitere Informationen zu Docker mit .NET finden Sie im Lernprogramm: Containerisieren einer .NET-App. Weitere Informationen zur Bereitstellung in Azure finden Sie im Lernprogramm: Bereitstellen eines WorkerDiensts in Azure.
Von Bedeutung
Wenn Sie Benutzergeheimnisse mit der Worker-Vorlage nutzen möchten, müssen Sie explizit auf das Microsoft.Extensions.Configuration.UserSecrets
NuGet-Paket verweisen.
Erweiterbarkeit des gehosteten Diensts
In der IHostedService-Schnittstelle sind zwei Methoden definiert:
Diese beiden Methoden dienen als Lebenszyklusmethoden – sie werden während des Start- und Stoppereignisses des Hosts aufgerufen.
Hinweis
Beim Überschreiben einer StartAsync- oder StopAsync-Methode müssen Sie die await
- und die base
-Klassenmethode aufrufen, um sicherzustellen, dass der Dienst gestartet und/oder ordnungsgemäß heruntergefahren wird.
Von Bedeutung
Die Schnittstelle dient als Einschränkung für generische Parameter für die AddHostedService<THostedService>(IServiceCollection) Erweiterungsmethode, was bedeutet, dass nur Implementierungen zulässig sind. Sie können die bereitgestellte BackgroundService mit einer Unterklasse verwenden oder Ihre eigene vollständig implementieren.
Signalvollendung
In den meisten gängigen Szenarien müssen Sie nicht explizit den Abschluss eines gehosteten Diensts signalisieren. Wenn der Host die Dienste startet, sind sie so konzipiert, dass sie ausgeführt werden, 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. Beachten Sie die folgende Worker
Klasse, um den Abschluss zu signalisieren:
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 schleift die BackgroundService.ExecuteAsync(CancellationToken) Methode nicht, und nach Abschluss wird IHostApplicationLifetime.StopApplication() aufgerufen.
Von Bedeutung
Dadurch wird dem Host signalisiert, dass er beendet werden soll, und ohne diesen Aufruf StopApplication
wird er weiterhin unbegrenzt ausgeführt. Wenn Sie beabsichtigen, einen kurzlebigen gehosteten Dienst auszuführen (einmalig ausgeführtes Szenario), und Sie die Worker-Vorlage verwenden möchten, müssen Sie StopApplication
aufrufen, um das Signal zu geben, den Host zu stoppen.
Weitere Informationen finden Sie unter:
- .NET Generic Host: IHostApplicationLifetime
- .NET Generic Host: Herunterfahren des Hosts
- .NET Generic Host: Hosting-Abschaltvorgang
Alternativer Ansatz
Verwenden Sie für eine kurzlebige App, die Abhängigkeitseinfügung, Protokollierung und Konfiguration benötigt, den generischen .NET-Host anstelle der Worker-Vorlage. Auf diese Weise können Sie diese Features ohne die Worker
Klasse verwenden. Ein einfaches Beispiel für eine kurzlebige App mit dem generischen Host kann eine Projektdatei wie die folgende definieren:
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>true</ImplicitUsings>
<RootNamespace>ShortLived.App</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="9.0.6" />
</ItemGroup>
</Project>
Möglicherweise sieht die Klasse Program
wie folgt aus:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddSingleton<JobRunner>();
using var host = builder.Build();
try
{
var runner = host.Services.GetRequiredService<JobRunner>();
await runner.RunAsync();
return 0; // success
}
catch (Exception ex)
{
var logger = host.Services.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "Unhandled exception occurred during job execution.");
return 1; // failure
}
Der vorangehende Code erstellt einen JobRunner
Dienst, bei dem es sich um eine benutzerdefinierte Klasse handelt, die die Logik für den auszuführenden Auftrag enthält. Die RunAsync
-Methode wird auf dem JobRunner
aufgerufen, und wenn sie erfolgreich abgeschlossen wird, gibt die App 0
zurück. Wenn eine unbehandelte Ausnahme auftritt, protokolliert sie den Fehler und gibt den Fehler zurück 1
.
In diesem einfachen Szenario könnte die JobRunner
Klasse wie folgt aussehen:
using Microsoft.Extensions.Logging;
internal sealed class JobRunner(ILogger<JobRunner> logger)
{
public async Task RunAsync()
{
logger.LogInformation("Starting job...");
// Simulate work
await Task.Delay(1000);
// Simulate failure
// throw new InvalidOperationException("Something went wrong!");
logger.LogInformation("Job completed successfully.");
}
}
Sie müssen der Methode RunAsync
offensichtlich echte Logik hinzufügen, aber in diesem Beispiel wird veranschaulicht, wie der generische Host für eine kurzlebige App ohne die Notwendigkeit einer Worker
Klasse und ohne explizite Signalisierung des Abschlusses des Hosts verwendet wird.
Siehe auch
- BackgroundService Unterklassen-Anleitungen
- Benutzerdefinierte IHostedService Implementierung: