Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Istnieje wiele powodów tworzenia długotrwałych usług, takich jak:
- Przetwarzanie danych o dużym obciążeniu CPU.
- Kolejkowanie elementów roboczych w tle.
- Wykonywanie operacji opartej na czasie zgodnie z harmonogramem.
Przetwarzanie usługi w tle zwykle nie obejmuje interfejsu użytkownika, ale interfejsy użytkownika można tworzyć wokół nich. We wczesnych dniach pracy z programem .NET Framework deweloperzy systemu Windows mogą tworzyć usługi systemu Windows do tych celów. Teraz na platformie .NET możesz użyć BackgroundService, który jest implementacją IHostedService, lub zaimplementować własne.
Platforma .NET nie jest już ograniczona do systemu Windows. Możesz tworzyć wieloplatformowe usługi w tle. Hostowane usługi są gotowe do rejestrowania, konfiguracji i wstrzykiwania zależności (DI). Są one częścią pakietu rozszerzeń bibliotek, co oznacza, że są one podstawowe dla wszystkich obciążeń platformy .NET, które współpracują z hostem ogólnym.
Ważne
Zainstalowanie zestawu .NET SDK powoduje również zainstalowanie Microsoft.NET.Sdk.Worker
i szablonu roboczego. Innymi słowy, po zainstalowaniu zestawu SDK platformy .NET można utworzyć nowy proces roboczy przy użyciu polecenia dotnet new worker. Jeśli używasz programu Visual Studio, szablon jest ukryty do momentu zainstalowania opcjonalnego obciążenia ASP.NET i tworzenia aplikacji internetowych.
Terminologia
Wiele terminów jest błędnie używanych synonimem. Ta sekcja definiuje niektóre z tych terminów, aby ich intencje w tym artykule były bardziej widoczne.
- Usługa w tle: Typ BackgroundService.
- Hostowana usługa: implementacje IHostedService, lub IHostedService samego siebie.
- Długotrwała usługa: Każda usługa, która jest uruchomiona w sposób ciągły.
- Usługasystemu Windows: infrastruktura usługi systemu Windows , pierwotnie skoncentrowana na programie .NET Framework, ale teraz dostępna za pośrednictwem platformy .NET.
- Usługa robocza: szablon usługi roboczej.
Szablon usługi procesu roboczego
Szablon usługi roboczej jest dostępny w .NET CLI i Visual Studio. Aby uzyskać więcej informacji, zobacz interfejs wiersza polecenia platformy .NET, dotnet new worker
— szablon. Szablon składa się z klasy Program
i klasy Worker
.
using App.WorkerService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();
IHost host = builder.Build();
host.Run();
Poprzednia Program
klasa:
- Tworzy HostApplicationBuilder.
- Wywołuje AddHostedService do rejestrowania
Worker
jako hostowaną usługę. - Tworzy IHost za pomocą „buildera”.
- Wywołuje
Run
w wystąpieniuhost
, które uruchamia aplikację.
Wartości domyślne szablonu
Szablon procesu roboczego domyślnie nie włącza odzyskiwania pamięci serwera ( GC), ponieważ istnieje wiele czynników, które odgrywają rolę w określaniu jego konieczności. Wszystkie scenariusze wymagające długotrwałych usług powinny uwzględniać wpływ na wydajność tego ustawienia domyślnego. Aby włączyć GC serwera, dodaj element ServerGarbageCollection
do pliku projektu.
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>
Kompromisy i zagadnienia
Włączone | Niepełnosprawny |
---|---|
Wydajne zarządzanie pamięcią: automatycznie odzyskuje nieużywaną pamięć, aby zapobiec wyciekom pamięci i zoptymalizować użycie zasobów. | Zwiększona wydajność w czasie rzeczywistym: pozwala uniknąć potencjalnych przerw lub przerw spowodowanych przez odzyskiwanie pamięci w aplikacjach wrażliwych na opóźnienia. |
Długoterminowa stabilność: pomaga utrzymać stabilną wydajność w długotrwałych usługach, zarządzając pamięcią w dłuższych okresach. | Wydajność zasobów: może oszczędzać zasoby CPU i pamięci w środowiskach o ograniczonych zasobach. |
Ograniczona konserwacja: minimalizuje potrzebę ręcznego zarządzania pamięcią, upraszczając konserwację. | Ręczna kontrola pamięci: zapewnia precyzyjną kontrolę nad pamięcią dla wyspecjalizowanych aplikacji. |
Przewidywalne zachowanie: przyczynia się do spójnego i przewidywalnego zachowania aplikacji. | Nadaje się do krótkotrwałych procesów: minimalizuje obciążenie związane z zarządzaniem pamięcią dla procesów krótkotrwałych lub efemerycznych. |
Aby uzyskać więcej informacji na temat zagadnień dotyczących wydajności, zobacz Serwer GC. Aby uzyskać więcej informacji na temat konfigurowania GC serwera, zobacz Przykłady konfiguracji GC serwera.
Klasa pracownika
Jeśli chodzi o Worker
element , szablon zapewnia prostą implementację.
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);
}
}
}
Poprzednia Worker
klasa jest podklasą BackgroundService, która implementuje IHostedServiceelement . Element BackgroundService jest abstract class
i wymaga, aby podklasa zaimplementowała BackgroundService.ExecuteAsync(CancellationToken). W ramach implementacji szablonu, ExecuteAsync
wykonuje pętlę raz na sekundę, logując bieżącą datę i godzinę, aż do momentu, gdy zasygnalizowane zostanie anulowanie procesu.
Plik projektu
Szablon roboczy opiera się na następującym pliku projektu Sdk
:
<Project Sdk="Microsoft.NET.Sdk.Worker">
Aby uzyskać więcej informacji, zobacz Zestawy SDK projektu .NET.
Pakiet NuGet
Aplikacja oparta na szablonie Procesu roboczego używa Microsoft.NET.Sdk.Worker
zestawu SDK i zawiera jawne odwołanie do pakietu Microsoft.Extensions.Hosting .
Kontenery i możliwość dostosowywania do chmury
W przypadku większości nowoczesnych obciążeń platformy .NET kontenery są realną opcją. Podczas tworzenia długotrwałej usługi na podstawie szablonu Proces roboczy w programie Visual Studio możesz skorzystać z wsparcia dla Docker. Spowoduje to utworzenie pliku Dockerfile , który konteneryzuje aplikację .NET. Plik Dockerfile to zestaw instrukcji tworzenia obrazu. W przypadku aplikacji .NET plik Dockerfile zwykle znajduje się w katalogu głównym obok pliku rozwiązania.
# 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"]
Powyższe kroki pliku Dockerfile obejmują:
- Ustawianie obrazu podstawowego z
mcr.microsoft.com/dotnet/runtime:8.0
jako aliasubase
. - Zmiana katalogu roboczego na /app.
- Ustawianie aliasu
build
na podstawie obrazumcr.microsoft.com/dotnet/sdk:8.0
. - Zmiana katalogu roboczego na /src.
- Kopiowanie zawartości i publikowanie aplikacji .NET:
- Aplikacja jest publikowana przy użyciu
dotnet publish
polecenia .
- Aplikacja jest publikowana przy użyciu
- Przekazywanie obrazu zestawu SDK platformy .NET z
mcr.microsoft.com/dotnet/runtime:8.0
(aliasubase
). - Kopiowanie opublikowanych danych wyjściowych kompilacji z /publish.
- Definiowanie punktu wejścia, który deleguje do
dotnet App.BackgroundService.dll
.
Wskazówka
McR to skrót od "Microsoft Container Registry" (Rejestr kontenerów firmy Microsoft) i jest współdzielonym katalogiem kontenerów firmy Microsoft z oficjalnego centrum Docker. Artykuł dotyczący wykazu kontenerów syndykates firmy Microsoft zawiera dodatkowe szczegóły.
W przypadku wyboru Dockera jako strategii wdrożenia dla usługi .NET Worker Service, należy wziąć pod uwagę kilka zagadnień dotyczących pliku projektu.
<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>
W poprzednim pliku projektu element <DockerDefaultTargetOS>
wskazuje Linux
jako swój cel. Aby skierować na kontenery systemu Windows, użyj Windows
zamiast tego.
Microsoft.VisualStudio.Azure.Containers.Tools.Targets
Pakiet NuGet jest automatycznie dodawany jako odwołanie do pakietu po wybraniu obsługi platformy Docker z szablonu.
Aby uzyskać więcej informacji na temat platformy Docker z platformą .NET, zobacz Samouczek: konteneryzowanie aplikacji .NET. Aby uzyskać więcej informacji na temat wdrażania na platformie Azure, zobacz Samouczek: wdrażanie usługi procesu roboczego na platformie Azure.
Ważne
Jeśli chcesz korzystać z tajemnic użytkownika z usługą Worker, musisz wyraźnie wskazać Microsoft.Extensions.Configuration.UserSecrets
pakiet NuGet.
Rozszerzalność usługi hostowanej
Interfejs IHostedService definiuje dwie metody:
Te dwie metody służą jako metody cyklu życia — wywoływane są odpowiednio podczas uruchamiania i zatrzymywania hosta.
Uwaga / Notatka
Podczas zastępowania metod StartAsync lub StopAsync należy wywołać metodę await
klasy oraz skorzystać z base
, aby upewnić się, że usługa zostanie uruchomiona i/lub prawidłowo zamknięta.
Ważne
Interfejs służy jako ograniczenie parametru typu ogólnego w AddHostedService<THostedService>(IServiceCollection) metodzie rozszerzenia, co oznacza, że dozwolone są tylko implementacje. Możesz korzystać z dostarczonej BackgroundService z podklasą lub zaimplementować własną od podstaw.
Uzupełnianie sygnału
W większości typowych scenariuszy nie trzeba jawnie sygnalizować ukończenia hostowanej usługi. Po uruchomieniu usług przez hosta są one przeznaczone do uruchamiania do momentu zatrzymania hosta. Jednak w niektórych scenariuszach może być konieczne sygnalizowanie ukończenia całej aplikacji hosta po ukończeniu pracy usługi. Aby zasygnalizować ukończenie, rozważ następującą Worker
klasę:
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();
}
}
W poprzednim kodzie metoda BackgroundService.ExecuteAsync(CancellationToken) nie tworzy pętli, a po zakończeniu wywołuje metodę IHostApplicationLifetime.StopApplication().
Ważne
Będzie to sygnalizować hostowi, że powinien zostać zatrzymany, a bez tego wywołania hosta StopApplication
będzie nadal działać w nieskończoność. Jeśli zamierzasz uruchomić krótkotrwałą hostowaną usługę (scenariusz jednorazowego uruchomienia) i chcesz użyć szablonu Worker, musisz wywołać metodę StopApplication
, aby zasygnalizować hostowi, aby się zatrzymał.
Aby uzyskać więcej informacji, zobacz:
- Host generacyjny platformy .NET: IHostApplicationLifetime
- Ogólny host .NET: wyłączanie hosta
- Ogólny host platformy .NET: proces zamykania hosta
Alternatywne podejście
W przypadku krótkotrwałej aplikacji wymagającej wstrzykiwania zależności, logowania i konfiguracji, użyj hosta ogólnego platformy .NET zamiast szablonu Pracownik. Dzięki temu można używać tych funkcji bez Worker
klasy. Prosty przykład krótkotrwałej aplikacji korzystającej z hosta ogólnego może definiować plik projektu w następujący sposób:
<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>
Jej Program
klasa może wyglądać mniej więcej tak:
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
}
Powyższy kod tworzy usługę, która jest klasą niestandardową zawierającą logikę JobRunner
do uruchomienia zadania. Metoda RunAsync
jest wywoływana na JobRunner
, a jeśli zakończy się pomyślnie, aplikacja zwróci 0
. Jeśli wystąpi nieobsługiwany wyjątek, rejestruje błąd i zwraca wartość 1
.
W tym prostym scenariuszu JobRunner
klasa może wyglądać następująco:
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.");
}
}
Oczywiście należy dodać prawdziwą logikę do metody RunAsync
, ale ten przykład pokazuje, jak używać ogólnego hosta dla krótkotrwałej aplikacji, bez konieczności używania klasy Worker
oraz jawnego sygnalizowania zakończenia działania hosta.
Zobacz także
- BackgroundService samouczki dotyczące podklas:
- Implementacja niestandardowa IHostedService :