Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Det finns många orsaker till att skapa långvariga tjänster, till exempel:
- Bearbetning av processorintensiva data.
- Placera arbetsuppgifter i kö för bakgrunden.
- Utföra en tidsbaserad åtgärd enligt ett schema.
Bearbetning av bakgrundstjänst omfattar vanligtvis inte något användargränssnitt, men UIs kan byggas runt dem. I början med .NET Framework kunde Windows-utvecklare skapa Windows-tjänster för dessa ändamål. Nu med .NET kan du använda BackgroundService, som är en implementering av IHostedServiceeller implementera din egen.
Med .NET är du inte längre begränsad till Windows. Du kan utveckla plattformsoberoende bakgrundstjänster. Värdbaserade tjänster är redo för loggning, konfiguration och beroendeinjektion (DI). De ingår i tilläggspaketet med bibliotek, vilket innebär att de är grundläggande för alla .NET-arbetsbelastningar som fungerar med generiska värd.
Viktig
När du installerar .NET SDK installeras även Microsoft.NET.Sdk.Worker
och arbetsmallen. När du har installerat .NET SDK kan du med andra ord skapa en ny arbetare med hjälp av kommandot dotnet new worker. Om du använder Visual Studio döljs mallen tills den valfria ASP.NET och webbutvecklingsarbetsbelastningen har installerats.
Terminologi
Många termer används av misstag synonymt. Det här avsnittet definierar några av dessa termer för att göra deras avsikt i den här artikeln tydligare.
- Background Service: BackgroundService-typen.
- värdbaserad tjänst: Implementeringar av IHostedServiceeller själva IHostedService.
- Långvarig tjänst: Alla tjänster som körs kontinuerligt.
- Windows Service: Windows Service infrastruktur, ursprungligen .NET Framework-centrerad men nu tillgänglig via .NET.
- Worker Service: Worker Service mallen.
Arbetarstjänstmall
Arbetstjänstmallen är tillgänglig i .NET CLI och Visual Studio. Mer information finns i .NET CLI, dotnet new worker
– template. Mallen består av en Program
- och Worker
-klass.
using App.WorkerService;
HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();
IHost host = builder.Build();
host.Run();
Föregående Program
-klass:
- Skapar en HostApplicationBuilder.
- Anropar AddHostedService för att registrera
Worker
som en värdbaserad tjänst. - Skapar en IHost med hjälp av byggaren.
- Anropar
Run
påhost
-instansen, som kör appen.
Standardinställningar för mallar
Worker-mallen aktiverar inte server skräpinsamling (GC) som standard, eftersom det finns många faktorer som spelar en roll för att fastställa dess nödvändighet. Alla scenarier som kräver långvariga tjänster bör ta hänsyn till prestandakonsekvenserna av den här standardinställningen. Om du vill aktivera server-GC lägger du till noden ServerGarbageCollection
i projektfilen:
<PropertyGroup>
<ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>
kompromisser och överväganden
Aktiverat | Handikappad |
---|---|
Effektiv minneshantering: Frigör automatiskt oanvänt minne för att förhindra minnesläckor och optimera resursanvändningen. | Förbättrad realtidsprestanda: Undviker potentiella pauser eller avbrott som orsakas av skräpinsamling i svarstidskänsliga program. |
Långsiktig stabilitet: Hjälper till att upprätthålla stabila prestanda i långvariga tjänster genom att hantera minne under längre perioder. | Resurseffektivitet: Kan spara processor- och minnesresurser i resursbegränsade miljöer. |
Minskat underhåll: Minimerar behovet av manuell minneshantering, vilket förenklar underhållet. | Manuell minneskontroll: Ger detaljerad kontroll över minnet för specialiserade program. |
Förutsägbart beteende: Bidrar till konsekvent och förutsägbart programbeteende. | Lämplig för kortvariga processer: Minimerar kostnaderna för skräpinsamling för kortvariga eller tillfälliga processer. |
Mer information om prestandaöverväganden finns i Server GC. Mer information om hur du konfigurerar server GC finns i Server GC-konfigurationsexempel.
Arbetarklass
När det gäller Worker
tillhandahåller mallen en enkel implementering.
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);
}
}
}
Föregående Worker
-klass är en underklass av BackgroundService, som implementerar IHostedService.
BackgroundService är en abstract class
och kräver att underklassen implementerar BackgroundService.ExecuteAsync(CancellationToken). I mallimplementeringen loopar ExecuteAsync
en gång per sekund och loggar aktuellt datum och tid tills processen signaleras avbrytas.
Projektfilen
Mallen Worker förlitar sig på följande projektfil Sdk
:
<Project Sdk="Microsoft.NET.Sdk.Worker">
Mer information finns i .NET-projekt-SDK:er.
NuGet-paket
En app som baseras på worker-mallen använder Microsoft.NET.Sdk.Worker
SDK och har en explicit paketreferens till Microsoft.Extensions.Hosting-paketet.
Containrar och molnanpassning
Med de flesta moderna .NET-arbetsbelastningar är containrar ett genomförbart alternativ. När du skapar en långvarig tjänst från Arbetsmallen i Visual Studio kan du välja att Docker-stöd. När du gör det skapas en Dockerfile- som containeriserar .NET-appen. En Dockerfile är en uppsättning instruktioner för att skapa en avbildning. För .NET-appar finns vanligtvis Dockerfile i roten i katalogen bredvid en lösningsfil.
# 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"]
I de föregående Dockerfile stegen ingår:
- Ange basavbildningen från
mcr.microsoft.com/dotnet/runtime:8.0
som aliasetbase
. - Ändra arbetskatalogen till /app.
- Ange
build
alias frånmcr.microsoft.com/dotnet/sdk:8.0
-avbildningen. - Ändra arbetskatalogen till /src.
- Kopiera innehållet och publicera .NET-appen:
- Appen publiceras med hjälp av kommandot
dotnet publish
.
- Appen publiceras med hjälp av kommandot
- Omlagra .NET SDK-bilden från
mcr.microsoft.com/dotnet/runtime:8.0
(aliasetbase
). - Kopiera publicerade build-utdata från /publish.
- Definiering av startpunkten, som delegerar till
dotnet App.BackgroundService.dll
.
Tips
MCR i mcr.microsoft.com
står för "Microsoft Container Registry" och är Microsofts syndikerade containerkatalog från den officiella Docker-hubben. Artikel om Microsoft-syndikerings containerkatalog innehåller ytterligare information.
När du riktar in dig på Docker som distributionsstrategi för .NET Worker Service finns det några saker att tänka på i projektfilen:
<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>
I föregående projektfil anger elementet <DockerDefaultTargetOS>
Linux
som mål. Använd Windows
i stället för att rikta in dig på Windows-containrar.
Microsoft.VisualStudio.Azure.Containers.Tools.Targets
NuGet-paketet läggs automatiskt till som en paketreferens när Docker-stöd väljs från mallen.
Mer information om Docker med .NET finns i Tutorial: Containerize a .NET app. Mer information om hur du distribuerar till Azure finns i Självstudie: Distribuera en arbetstjänst till Azure.
Viktig
Om du vill använda användarhemligheter med Worker-mallen måste du uttryckligen ange Microsoft.Extensions.Configuration.UserSecrets
NuGet-paketet.
Utökningsbarhet för värdbaserad tjänst
Gränssnittet IHostedService definierar två metoder:
Dessa två metoder fungerar som livscykel metoder – de anropas under värdstarts- respektive stopphändelser.
Obs
När du åsidosättar antingen StartAsync eller StopAsync metoder måste du anropa och await
base
-klassmetoden för att säkerställa att tjänsten startas och/eller stängs av korrekt.
Viktig
Gränssnittet fungerar som en parameterbegränsning av generisk typ för AddHostedService<THostedService>(IServiceCollection)-tilläggsmetoden, vilket innebär att endast implementeringar tillåts. Du kan använda den angivna BackgroundService med en underklass eller implementera din egen helt.
Signalera färdigställande
I de vanligaste scenarierna behöver du inte uttryckligen signalera slutförandet av en värdbaserad tjänst. När värden startar tjänsterna är de avsedda att köras tills värden stoppas. I vissa scenarier kan du dock behöva signalera slutförandet av hela värdprogrammet när tjänsten är klar. Tänk på följande Worker
-klass för att signalera slutförandet:
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();
}
}
I föregående kod loopar inte metoden BackgroundService.ExecuteAsync(CancellationToken) och när den är klar anropas IHostApplicationLifetime.StopApplication().
Viktig
Detta kommer att signalera till värden att den ska stoppa, och utan det här anropet till StopApplication
kommer värden att fortsätta köras på obestämd tid. Om du tänker köra en kortvarig värdbaserad tjänst (kör en gång i det aktuella scenariot) och du vill använda Worker-mallen måste du anropa StopApplication
för att ge värden en signal om att stoppa.
Mer information finns i:
- .NET Generic Host: IHostApplicationLifetime
- .NET Generic Host: Nedstängning
- .NET Generic Host: Avstängning av hostingtjänstprocess
Alternativt tillvägagångssätt
För en kortlivad app som behöver beroendeinjektion, loggning och konfiguration, använder du den generiska .NET-värden i stället för Worker-mallen. På så sätt kan du använda dessa funktioner utan Worker
klassen. Ett enkelt exempel på en kortlivad app som använder den generiska värden kan definiera en projektfil enligt följande:
<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>
Dess Program
-klass kan se ut ungefär så här:
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
}
Föregående kod skapar en JobRunner
tjänst, som är en anpassad klass som innehåller logiken för jobbet som ska köras. Metoden RunAsync
anropas på JobRunner
, och om den slutförs framgångsrikt returnerar appen 0
. Om ett ohanterat undantag inträffar loggar det felet och returnerar 1
.
I det här enkla scenariot JobRunner
kan klassen se ut så här:
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.");
}
}
Du skulle naturligtvis behöva lägga till verklig logik i RunAsync
metoden, men det här exemplet visar hur du använder den generiska värd för en kortlivad app utan att behöva en Worker
klass, och utan att uttryckligen behöva signalera slutförandet av värdens.
Se även
- handledning för BackgroundService subklass:
- Anpassad IHostedService implementation: