Arbetstjänster i .NET

Det finns många orsaker till att skapa långvariga tjänster, till exempel:

  • Bearbetning av processorintensiva data.
  • Köa arbetsobjekt i 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 av dessa skäl. Nu med .NET kan du använda BackgroundService, som är en implementering av IHostedService, eller 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 beroendeinmatning (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 den generiska värden.

Viktigt!

När du installerar .NET SDK installeras även arbetsmallen Microsoft.NET.Sdk.Worker och . 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. I det här avsnittet finns det definitioner för vissa av dessa termer för att göra avsikten tydligare.

  • Bakgrundstjänst: Refererar till BackgroundService typen.
  • Värdbaserad tjänst: Implementeringar av IHostedService, eller refererar till IHostedService sig själv.
  • Långvarig tjänst: Alla tjänster som körs kontinuerligt.
  • Windows Service: Windows Service-infrastrukturen , ursprungligen .NET Framework-centrerad men nu tillgänglig via .NET.
  • Arbetstjänst: Refererar till arbetstjänstmallen .

Arbetstjänstmall

Arbetstjänstmallen är tillgänglig för .NET CLI och Visual Studio. Mer information finns i .NET CLI, dotnet new worker – mall. 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:

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 ServerGarbageCollection noden i projektfilen:

<PropertyGroup>
    <ServerGarbageCollection>true</ServerGarbageCollection>
</PropertyGroup>

Kompromisser och överväganden

Aktiverat Inaktiverat
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 Konfigurationsexempel för server GC.

Arbetarklass

När det Workergäller ger 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 looparna 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:t 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 Worker-mallen i Visual Studio kan du välja Docker-support. 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 Dockerfile vanligtvis 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 AS base
WORKDIR /app

FROM mcr.microsoft.com/dotnet/sdk:8.0 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"]

Föregående Dockerfile-steg är:

  • Ange basavbildningen från mcr.microsoft.com/dotnet/runtime:8.0 som alias base.
  • Ändra arbetskatalogen till /app.
  • Ange aliaset build från bilden mcr.microsoft.com/dotnet/sdk:8.0 .
  • Ändra arbetskatalogen till /src.
  • Kopiera innehållet och publicera .NET-appen:
  • Vidarebefordra .NET SDK-avbildningen från mcr.microsoft.com/dotnet/runtime:8.0 (aliaset base ).
  • Kopiera publicerade build-utdata från /publish.
  • Definiera startpunkten, som delegerar till dotnet App.BackgroundService.dll.

Dricks

MCR i mcr.microsoft.com står för "Microsoft Container Registry" och är Microsofts syndikerade containerkatalog från den officiella Docker-hubben. Artikeln om containerkatalogen för Microsoft-syndikat 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="8.0.0" />
    <PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.5" />
  </ItemGroup>
</Project>

I den föregående projektfilen anger Linux elementet <DockerDefaultTargetOS> som mål. Använd i stället för att rikta in dig på Windows-containrar Windows . 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 Självstudie: Containerisera en .NET-app. Mer information om hur du distribuerar till Azure finns i Självstudie: Distribuera en arbetstjänst till Azure.

Viktigt!

Om du vill använda användarhemligheter med arbetsmallen måste du uttryckligen referera Microsoft.Extensions.Configuration.UserSecrets till NuGet-paketet.

Utökningsbarhet för värdbaserad tjänst

Gränssnittet IHostedService definierar två metoder:

Dessa två metoder fungerar som livscykelmetoder – de anropas under värdstart respektive stopphändelser.

Kommentar

När du åsidosättar någon av StartAsync metoderna måste StopAsync du anropa och awaitbase klassmetoden för att säkerställa att tjänsten startar och/eller stängs av korrekt.

Viktigt!

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 tillhandahållna BackgroundService med en underklass eller implementera din egen helt och hållet.

Signalen har slutförts

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 utformade för 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 ExecuteAsync loopar inte metoden och när den är klar anropas IHostApplicationLifetime.StopApplication()den .

Viktigt!

Detta kommer att signalera till värden att den ska stoppas, och utan det här anropet till StopApplication värden fortsätter att köras på obestämd tid.

Mer information finns i:

Se även