Werkrolservices in .NET

Er zijn talloze redenen voor het maken van langlopende services, zoals:

  • Cpu-intensieve gegevens verwerken.
  • Werkitems in de wachtrij plaatsen op de achtergrond.
  • Een tijdgebaseerde bewerking uitvoeren op basis van een schema.

Verwerking van achtergrondservices omvat meestal geen gebruikersinterface (UI), maar UIs kunnen er omheen worden gebouwd. In de vroege dagen met .NET Framework konden Windows-ontwikkelaars Om deze redenen Windows Services maken. Met .NET kunt u nu de BackgroundService, een implementatie van IHostedServiceof uw eigen implementatie gebruiken.

Met .NET bent u niet langer beperkt tot Windows. U kunt platformoverschrijdende achtergrondservices ontwikkelen. Gehoste services zijn gereed voor logboekregistratie, configuratie en afhankelijkheidsinjectie (DI). Ze maken deel uit van de uitbreidingssuite met bibliotheken, wat betekent dat ze fundamenteel zijn voor alle .NET-workloads die met de algemene host werken.

Belangrijk

Als u de .NET SDK installeert, worden ook de Microsoft.NET.Sdk.Worker en de werkrolsjabloon geïnstalleerd. Met andere woorden, nadat u de .NET SDK hebt geïnstalleerd, kunt u een nieuwe werkrol maken met behulp van de opdracht nieuwe werkrol dotnet. Als u Visual Studio gebruikt, wordt de sjabloon verborgen totdat de optionele workload voor ASP.NET en webontwikkeling is geïnstalleerd.

Terminologie

Veel termen worden per ongeluk gebruikt. In deze sectie zijn er definities voor sommige van deze termen om hun intentie duidelijker te maken.

  • Background Service: verwijst naar het BackgroundService type.
  • Gehoste service: implementaties van IHostedService, of verwijzen naar de IHostedService zelf.
  • Langlopende service: elke service die continu wordt uitgevoerd.
  • Windows-service: de Windows Service-infrastructuur , oorspronkelijk .NET Framework gericht, maar nu toegankelijk via .NET.
  • Worker Service: verwijst naar de worker-servicesjabloon .

Worker Service-sjabloon

De worker-servicesjabloon is beschikbaar voor de .NET CLI en Visual Studio. Zie .NET CLI, dotnet new worker -sjabloon voor meer informatie. De sjabloon bestaat uit een Program en Worker klasse.

using App.WorkerService;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();

IHost host = builder.Build();
host.Run();

De voorgaande Program klasse:

  • Hiermee maakt u een HostApplicationBuilder.
  • Roept AddHostedService aan om de Worker als een gehoste service te registreren.
  • Bouwt een IHost van de opbouwfunctie.
  • Roept Run het host exemplaar aan, waarmee de app wordt uitgevoerd.

Standaardinstellingen voor sjablonen

De werkrolsjabloon schakelt standaard de garbagecollection (GC) van de server niet in, omdat er talloze factoren zijn die een rol spelen bij het bepalen van de noodzaak ervan. Alle scenario's waarvoor langlopende services zijn vereist, moeten rekening houden met de gevolgen voor de prestaties van deze standaardinstelling. Als u server-GC wilt inschakelen, voegt u het ServerGarbageCollection knooppunt toe aan het projectbestand:

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

Compromissen en overwegingen

Ingeschakeld Uitgeschakeld
Efficiënt geheugenbeheer: maakt ongebruikt geheugen automatisch vrij om geheugenlekken te voorkomen en resourcegebruik te optimaliseren. Verbeterde realtime prestaties: vermijdt mogelijke onderbrekingen of onderbrekingen die worden veroorzaakt door garbagecollection in latentiegevoelige toepassingen.
Langetermijnstabiliteit: helpt stabiele prestaties in langlopende services te behouden door het geheugen gedurende langere perioden te beheren. Resource-efficiëntie: kan CPU- en geheugenresources besparen in omgevingen met beperkte resources.
Verminderd onderhoud: minimaliseert de noodzaak van handmatig geheugenbeheer, waardoor onderhoud wordt vereenvoudigd. Handmatig geheugenbeheer: biedt nauwkeurige controle over het geheugen voor gespecialiseerde toepassingen.
Voorspelbaar gedrag: draagt bij aan consistent en voorspelbaar toepassingsgedrag. Geschikt voor kortdurende processen: minimaliseert de overhead van garbagecollection voor kortstondige of kortstondige processen.

Zie Server GC voor meer informatie over prestatieoverwegingen. Zie Voorbeelden van server GC-configuratie voor meer informatie over het configureren van server-GC.

Werkrolklasse

Wat de Workersjabloon betreft, biedt de sjabloon een eenvoudige implementatie.

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);
        }
    }
}

De voorgaande Worker klasse is een subklasse van BackgroundService, die implementeert IHostedService. Dit BackgroundService is een abstract class en vereist dat de subklasse wordt geïmplementeerd BackgroundService.ExecuteAsync(CancellationToken). In de sjabloon-implementatie worden de ExecuteAsync lussen eenmaal per seconde geregistreerd, waarbij de huidige datum en tijd worden geregistreerd totdat het proces wordt gesignaleerd om te annuleren.

Het projectbestand

De worker-sjabloon is afhankelijk van het volgende projectbestand Sdk:

<Project Sdk="Microsoft.NET.Sdk.Worker">

Zie .NET-project-SDK's voor meer informatie.

NuGet-pakket

Een app op basis van de Worker-sjabloon maakt gebruik van de Microsoft.NET.Sdk.Worker SDK en heeft een expliciete pakketverwijzing naar het Pakket Microsoft.Extensions.Hosting .

Containers en cloudaanpassing

Bij de meeste moderne .NET-workloads zijn containers een haalbare optie. Wanneer u een langlopende service maakt vanuit de Worker-sjabloon in Visual Studio, kunt u zich aanmelden voor Docker-ondersteuning. Hiermee maakt u een Dockerfile waarmee uw .NET-app in een container wordt geplaatst. Een Dockerfile is een set instructies voor het bouwen van een installatiekopieën. Voor .NET-apps bevindt het Dockerfile zich meestal in de hoofdmap van de map naast een oplossingsbestand.

# 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"]

De voorgaande Dockerfile-stappen omvatten:

  • De basisinstallatiekopieën mcr.microsoft.com/dotnet/runtime:8.0 instellen als de alias base.
  • De werkmap wijzigen in /app.
  • build De alias van de mcr.microsoft.com/dotnet/sdk:8.0 afbeelding instellen.
  • De werkmap wijzigen in /src.
  • De inhoud kopiëren en de .NET-app publiceren:
    • De app wordt gepubliceerd met behulp van de dotnet publish opdracht.
  • De .NET SDK-installatiekopieën van mcr.microsoft.com/dotnet/runtime:8.0 (de base alias) doorsturen.
  • De gepubliceerde build-uitvoer van de /publish kopiëren.
  • Het beginpunt definiëren, waarnaar wordt dotnet App.BackgroundService.dllgedelegeerd.

Tip

De MCR in mcr.microsoft.com staat voor 'Microsoft Container Registry' en is de gesyndiceerde containercatalogus van Microsoft van de officiële Docker-hub. Het artikel over de containercatalogus van Microsoft syndicaten bevat aanvullende informatie.

Wanneer u Docker als implementatiestrategie voor uw .NET Worker-service richt, zijn er enkele overwegingen in het projectbestand:

<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>

In het voorgaande projectbestand geeft Linux het <DockerDefaultTargetOS> element het doel op. Als u windows-containers wilt gebruiken, gebruikt Windows u in plaats daarvan. Het Microsoft.VisualStudio.Azure.Containers.Tools.Targets NuGet-pakket wordt automatisch toegevoegd als pakketreferentie wanneer Docker-ondersteuning is geselecteerd in de sjabloon.

Zie Zelfstudie: Een .NET-app in een container opslaan voor meer informatie over Docker met .NET. Zie zelfstudie: Een werkrolservice implementeren in Azure voor meer informatie over het implementeren in Azure.

Belangrijk

Als u gebruikersgeheimen wilt gebruiken met de werkrolsjabloon, moet u expliciet verwijzen naar het Microsoft.Extensions.Configuration.UserSecrets NuGet-pakket.

Uitbreidbaarheid van gehoste services

De IHostedService interface definieert twee methoden:

Deze twee methoden fungeren als levenscyclusmethoden : ze worden respectievelijk aangeroepen tijdens het starten en stoppen van de host.

Notitie

Wanneer u een StartAsync of StopAsync meer methoden overschrijft, moet u aanroepen en await de base klassemethode om ervoor te zorgen dat de service wordt gestart en/of correct wordt afgesloten.

Belangrijk

De interface fungeert als een algemene parameterbeperking voor de AddHostedService<THostedService>(IServiceCollection) extensiemethode, wat betekent dat alleen implementaties zijn toegestaan. U kunt de meegeleverde BackgroundService subklasse gebruiken of uw eigen subklasse implementeren.

Signaalvoltooiing

In de meest voorkomende scenario's hoeft u niet expliciet de voltooiing van een gehoste service aan te geven. Wanneer de host de services start, zijn ze ontworpen om te worden uitgevoerd totdat de host is gestopt. In sommige scenario's moet u echter mogelijk aangeven dat de volledige hosttoepassing is voltooid wanneer de service is voltooid. Houd rekening met de volgende Worker klasse om de voltooiing aan te geven:

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();
    }
}

In de voorgaande code wordt de ExecuteAsync methode niet lus uitgevoerd en wanneer deze is voltooid, wordt deze aangeroepen IHostApplicationLifetime.StopApplication().

Belangrijk

Dit geeft aan dat de host moet worden gestopt en zonder deze aanroep naar StopApplication de host voor onbepaalde tijd wordt uitgevoerd.

Zie voor meer informatie:

Zie ook