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.
Tips/Råd
Det här innehållet är ett utdrag från eBook, .NET Microservices Architecture for Containerized .NET Applications, tillgängligt på .NET Docs eller som en kostnadsfri nedladdningsbar PDF som kan läsas offline.
              
               
              
              
            
Bakgrundsaktiviteter och schemalagda jobb kan behöva användas i alla program, oavsett om de följer arkitekturmönstret för mikrotjänster eller inte. Skillnaden när du använder en arkitektur för mikrotjänster är att du kan implementera bakgrundsaktiviteten i en separat process/container för värdtjänster så att du kan skala ned den/upp baserat på dina behov.
Från en allmän synvinkel i .NET kallade vi den här typen av uppgifter värdbaserade tjänster, eftersom de är tjänster/logik som du är värd för i din värd/program/mikrotjänst. Observera att i det här fallet innebär den värdbaserade tjänsten helt enkelt en klass med bakgrundsaktivitetslogik.
Sedan .NET Core 2.0 tillhandahåller ramverket ett nytt gränssnitt med namnet IHostedService som hjälper dig att enkelt implementera värdbaserade tjänster. Den grundläggande tanken är att du kan registrera flera bakgrundsuppgifter (värdtjänster) som körs i bakgrunden när din webbvärd eller värd körs, som visas i bild 6–26.
               
              
            
Bild 6-26. Använda IHostedService i en WebHost jämfört med en värd
ASP.NET Core 1.x och 2.x stöd IWebHost för bakgrundsprocesser i webbappar. .NET Core 2.1 och senare versioner stöder IHost bakgrundsprocesser med vanliga konsolappar. Observera skillnaden mellan WebHost och Host.
En WebHost (basklass som implementerar IWebHost) i ASP.NET Core 2.0 är den infrastrukturartefakt som du använder för att tillhandahålla HTTP-serverfunktioner i processen, till exempel när du implementerar en MVC-webbapp eller webb-API-tjänst. Det ger all den nya infrastrukturens godhet i ASP.NET Core, så att du kan använda beroendeinmatning, infoga mellanprogram i pipelinen för begäran och liknande. 
              WebHost använder dessa exakt samma IHostedServices för bakgrundsaktiviteter.
En Host (basklass som implementerar IHost) introducerades i .NET Core 2.1. I grund och botten Host kan du ha en liknande infrastruktur än vad du har med WebHost (beroendeinmatning, värdbaserade tjänster osv.), men i det här fallet vill du bara ha en enkel och lättare process som värd, utan något relaterat till MVC, webb-API eller HTTP-serverfunktioner.
Därför kan du välja och antingen skapa en specialiserad värdprocess med IHost för att hantera de hostade tjänsterna och inget annat, en sådan mikrotjänst som görs endast för att hosta IHostedServices, eller alternativt kan du utöka en befintlig ASP.NET Core WebHost, till exempel en befintlig ASP.NET Core Web API eller MVC-app.
Varje metod har fördelar och nackdelar beroende på dina affärs- och skalbarhetsbehov. Den nedersta raden är i princip att om dina bakgrundsuppgifter inte har något att göra med HTTP (IWebHost) bör du använda IHost.
Registrera värdbaserade tjänster i ditt webbhotell eller värdmiljö
Nu ska vi öka detaljnivån ytterligare i IHostedService gränssnittet eftersom dess användning är ganska lik i en WebHost eller i en Host.
SignalR är ett exempel på en artefakt som använder värdbaserade tjänster, men du kan också använda den för mycket enklare saker som:
- En bakgrundsaktivitet söker efter ändringar i en databas.
- En schemalagd uppgift som uppdaterar vissa cacheminnen med jämna mellanrum.
- En implementering av QueueBackgroundWorkItem som gör att en uppgift kan köras i en bakgrundstråd.
- Bearbeta meddelanden från en meddelandekö i bakgrunden av en webbapp samtidigt som du delar vanliga tjänster som ILogger.
- En bakgrundsprocess startade med Task.Run().
Du kan i princip avlasta någon av dessa åtgärder till en bakgrundsaktivitet som implementerar IHostedService.
Hur du lägger till en eller flera IHostedServices i din WebHost eller Host är genom att registrera dem via AddHostedService tilläggsmetoden i en ASP.NET Core WebHost (eller i en Host i .NET Core 2.1 och senare). I grund och botten måste du registrera värdbaserade tjänster inom programstart i Program.cs.
//Other DI registrations;
// Register Hosted Services
builder.Services.AddHostedService<GracePeriodManagerService>();
builder.Services.AddHostedService<MyHostedServiceB>();
builder.Services.AddHostedService<MyHostedServiceC>();
//...
I den koden är den GracePeriodManagerService värdbaserade tjänsten verklig kod från mikrotjänsten Ordering Business i eShopOnContainers, medan de andra två bara är två ytterligare exempel.
              IHostedService Körning av bakgrundsaktiviteten samordnas med applikationens livslängd (värd eller mikrotjänst). Du registrerar uppgifter när programmet startar och du har möjlighet att utföra vissa åtgärder eller rensa upp när programmet stängs av.
Utan att använda IHostedServicekan du alltid starta en bakgrundstråd för att köra en uppgift. Skillnaden ligger precis vid appens tidpunkt för avstängning när den tråden helt enkelt skulle stoppas utan att ha möjlighet att utföra ordentliga rensningsåtgärder.
Gränssnittet IHostedService
När du registrerar en IHostedService anropar .NET metoderna StartAsync() och StopAsync() av din IHostedService-typ under programstart och stopparna. Mer information finns i IHostedService-gränssnittet.
Som du kan föreställa dig kan du skapa flera implementeringar av IHostedService och registrera var och en av dem i Program.cs, som du visade tidigare. Alla dessa värdbaserade tjänster startas och stoppas tillsammans med programmet/mikrotjänsten.
Som utvecklare ansvarar du för att hantera avslutandet av dina tjänster när värden utlöser StopAsync()-metoden.
Implementera IHostedService med en anpassad värdbaserad tjänstklass som härleds från backgroundservice-basklassen
Du kan gå vidare och skapa din anpassade värdbaserade tjänstklass från grunden och implementera IHostedService, som du behöver göra när du använder .NET Core 2.0 och senare.
Men eftersom de flesta bakgrundsaktiviteter har liknande behov när det gäller hantering av annulleringstoken och andra typiska åtgärder finns det en praktisk abstrakt basklass som du kan härleda från, med namnet BackgroundService (tillgänglig sedan .NET Core 2.1).
Den här klassen innehåller det huvudsakliga arbete som krävs för att konfigurera bakgrundsaktiviteten.
Nästa kod är den abstrakta BackgroundService-basklassen som implementeras i .NET.
// Copyright (c) .NET Foundation. Licensed under the Apache License, Version 2.0.
/// <summary>
/// Base class for implementing a long running <see cref="IHostedService"/>.
/// </summary>
public abstract class BackgroundService : IHostedService, IDisposable
{
    private Task _executingTask;
    private readonly CancellationTokenSource _stoppingCts =
                                                   new CancellationTokenSource();
    protected abstract Task ExecuteAsync(CancellationToken stoppingToken);
    public virtual Task StartAsync(CancellationToken cancellationToken)
    {
        // Store the task we're executing
        _executingTask = ExecuteAsync(_stoppingCts.Token);
        // If the task is completed then return it,
        // this will bubble cancellation and failure to the caller
        if (_executingTask.IsCompleted)
        {
            return _executingTask;
        }
        // Otherwise it's running
        return Task.CompletedTask;
    }
    public virtual async Task StopAsync(CancellationToken cancellationToken)
    {
        // Stop called without start
        if (_executingTask == null)
        {
            return;
        }
        try
        {
            // Signal cancellation to the executing method
            _stoppingCts.Cancel();
        }
        finally
        {
            // Wait until the task completes or the stop token triggers
            await Task.WhenAny(_executingTask, Task.Delay(Timeout.Infinite,
                                                          cancellationToken));
        }
    }
    public virtual void Dispose()
    {
        _stoppingCts.Cancel();
    }
}
När du härleder från den tidigare abstrakta basklassen, tack vare den ärvda implementeringen, behöver du bara implementera ExecuteAsync() metoden i din egen anpassade värdbaserade tjänstklass, som i följande förenklade kod från eShopOnContainers som avsöker en databas och publicerar integrationshändelser i Event Bus när det behövs.
public class GracePeriodManagerService : BackgroundService
{
    private readonly ILogger<GracePeriodManagerService> _logger;
    private readonly OrderingBackgroundSettings _settings;
    private readonly IEventBus _eventBus;
    public GracePeriodManagerService(IOptions<OrderingBackgroundSettings> settings,
                                     IEventBus eventBus,
                                     ILogger<GracePeriodManagerService> logger)
    {
        // Constructor's parameters validations...
    }
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        _logger.LogDebug($"GracePeriodManagerService is starting.");
        stoppingToken.Register(() =>
            _logger.LogDebug($" GracePeriod background task is stopping."));
        while (!stoppingToken.IsCancellationRequested)
        {
            _logger.LogDebug($"GracePeriod task doing background work.");
            // This eShopOnContainers method is querying a database table
            // and publishing events into the Event Bus (RabbitMQ / ServiceBus)
            CheckConfirmedGracePeriodOrders();
            try {
                    await Task.Delay(_settings.CheckUpdateTime, stoppingToken);
                }
            catch (TaskCanceledException exception) {
                    _logger.LogCritical(exception, "TaskCanceledException Error", exception.Message);
                }
        }
        _logger.LogDebug($"GracePeriod background task is stopping.");
    }
    .../...
}
I det här specifika fallet för eShopOnContainers kör den en programmetod som kör frågor mot en databastabell och letar efter order med ett specifikt tillstånd och när ändringar tillämpas publicerar den integreringshändelser via händelsebussen (under den kan den använda RabbitMQ eller Azure Service Bus).
Du kan naturligtvis köra andra bakgrundsuppgifter för verksamheten i stället.
Som standardinställning anges annulleringstoken med en tidsgräns på 5 sekunder, men du kan ändra det värdet när du bygger ditt WebHost med UseShutdownTimeout-tillägget för IWebHostBuilder. Det innebär att vår tjänst förväntas stängas av inom 5 sekunder, annars kommer den att avslutas abrupt.
Följande kod skulle ändra den tiden till 10 sekunder.
WebHost.CreateDefaultBuilder(args)
    .UseShutdownTimeout(TimeSpan.FromSeconds(10))
    ...
Sammanfattningsklassdiagram
Följande bild visar en visuell sammanfattning av de klasser och gränssnitt som ingår i implementeringen av IHostedServices.
               
              
            
Bild 6-27. Klassdiagram som visar flera klasser och gränssnitt relaterade till IHostedService
Klassdiagram: IWebHost och IHost kan vara värdar för många tjänster som ärver från BackgroundService, som implementerar IHostedService.
Överväganden vid distribution och slutsatser
Observera att det sätt på vilket du distribuerar din ASP.NET Core WebHost eller .NET Host kan påverka den slutliga lösningen. Om du till exempel distribuerar din WebHost på IIS eller en vanlig Azure App Service kan värden stängas av på grund av att apppoolen återvinns. Men om du distribuerar din värd som en container till en orkestrerare som Kubernetes kan du kontrollera det garanterade antalet aktiva instanser av din värd. Dessutom kan du överväga andra metoder i molnet som är särskilt gjorda för dessa scenarier, till exempel Azure Functions. Om du behöver att tjänsten körs hela tiden och distribueras på en Windows Server kan du använda en Windows-tjänst.
Men även för en WebHost distribuerad till en apppool finns det scenarier som repopulering eller tömning av programmets minnesinterna cacheminne som fortfarande skulle vara tillämpligt.
Gränssnittet IHostedService ger ett bekvämt sätt att starta bakgrundsaktiviteter i ett ASP.NET Core-webbprogram (i .NET Core 2.0 och senare versioner) eller i valfri process/värd (med början i .NET Core 2.1 med IHost). Den största fördelen är den möjlighet du får med den smidiga annulleringen för att städa upp i koden för dina bakgrundsuppgifter vid avstängning av värden.
Ytterligare resurser
- Skapa en schemalagd aktivitet i ASP.NET Core/Standard 2.0 
 https://blog.maartenballiauw.be/post/2017/08/01/building-a-scheduled-cache-updater-in-aspnet-core-2.html
- Implementera IHostedService i ASP.NET Core 2.0 
 https://www.stevejgordon.co.uk/asp-net-core-2-ihostedservice
- GenericHost-exempel med ASP.NET Core 2.1 
 https://github.com/aspnet/Hosting/tree/release/2.1/samples/GenericHostSample