Sdílet prostřednictvím


Obecný hostitel .NET

V tomto článku se dozvíte o různých vzorech konfigurace a vytvoření obecného hostitele .NET, který je k dispozici v balíčku NuGet Microsoft.Extensions.Hosting . Generický hostitel .NET je odpovědný za řízení spuštění a správu životního cyklu aplikace. Šablony služby Pracovních procesů vytvářejí obecného hostitele .NET. HostApplicationBuilder Obecný hostitel lze použít s jinými typy aplikací .NET, jako jsou konzolové aplikace.

Hostitel je objekt, který zapouzdřuje prostředky a funkce životního cyklu aplikace, například:

  • Injektáž závislostí (DI)
  • Protokolování
  • Konfigurace
  • Vypnutí aplikace
  • IHostedService implementace

Když se hostitel spustí, volá IHostedService.StartAsync každou implementaci zaregistrované IHostedService v kolekci hostovaných služeb kontejneru služby. V aplikaci pracovní služby mají všechny IHostedService implementace, které obsahují BackgroundService instance, volané metody BackgroundService.ExecuteAsync .

Hlavním důvodem zahrnutí všech vzájemně závislých prostředků aplikace v jednom objektu je správa životnosti: kontrola nad spuštěním aplikace a řádné vypnutí.

Možnosti konfigurace hostitele

.NET poskytuje dva přístupy ke konfiguraci a vytvoření obecného hostitele:

  • IHostApplicationBuilder (Host.CreateApplicationBuilder): Tento přístup zavedený v .NET 6 používá lineární styl konfigurace na základě vlastností. Služby, konfigurace a protokolování se konfigurují přímým přístupem k vlastnostem objektu tvůrce (například builder.Services, ). builder.Configuration Tento přístup se doporučuje pro nové projekty a je výchozím nastavením v aktuálních šablonách .NET.

  • IHostBuilder(Host.CreateDefaultBuilder): Toto je tradiční přístup založený na zpětném volání, kde se konfigurace provádí prostřednictvím zřetězených rozšiřujících metod (například ConfigureServices, ). ConfigureAppConfiguration I když je tento starší přístup plně podporovaný, je nejvhodnější pro zachování kompatibility s existujícími základy kódu.

Oba přístupy poskytují stejné základní funkce a výchozí chování. Vyberte IHostApplicationBuilder pro nové projekty tak, aby se sladily s moderními .NET vzory a jednodušším konfiguračním kódem. Používá se IHostBuilder při údržbě existujících aplikací nebo v případech, kdy knihovny třetích stran vyžadují vzor založený na zpětném volání.

Nastavení hostitele

Hostitel je obvykle nakonfigurovaný, sestavený a spouštěný kódem ve Program třídě. Metoda Main:

Šablony služby pracovních procesů .NET vygenerují následující kód pro vytvoření obecného hostitele:

using Example.WorkerService;

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

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

Další informace o pracovních službách naleznete v tématu Služby pracovních procesů v .NET.

Nastavení generátoru hostitelů

Metoda CreateApplicationBuilder:

  • Nastaví kořen obsahu na cestu vrácenou GetCurrentDirectory().
  • Načte konfiguraci hostingu z:
    • Proměnné prostředí s předponou DOTNET_.
    • Argumenty příkazového řádku
  • Načte konfiguraci aplikace z:
    • appsettings.json.
    • nastavení aplikace. {Environment}.json.
    • Správce tajných kódů při spuštění aplikace v Development prostředí
    • Proměnné prostředí.
    • Argumenty příkazového řádku
  • Přidá následující zprostředkovatele protokolování:
    • Konzola
    • Ladění
    • ZdrojUdálostí
    • EventLog (pouze při spuštění ve Windows)
  • Povolí ověřování oboru a ověřování závislostí, když je prostředí .

Jedná se HostApplicationBuilder.Services o Microsoft.Extensions.DependencyInjection.IServiceCollection instanci. Tyto služby slouží k vytvoření IServiceProvider injektáže závislostí k vyřešení registrovaných služeb.

Služby poskytované frameworkem

Při volání IHostBuilder.Build() nebo volání HostApplicationBuilder.Build() se automaticky zaregistrují následující služby:

Další scénáristické nástroje pro sestavení hostitelů

Pokud vytváříte pro web nebo píšete distribuovanou aplikaci, možná budete muset použít jiného tvůrce hostitelů. Podívejte se na následující seznam dalších tvůrce hostitelů:

IHostApplicationLifetime

Vložte službu IHostApplicationLifetime do libovolné třídy pro zpracování úloh po spuštění a řízeném vypnutí. Tři vlastnosti na rozhraní jsou tokeny pro zrušení používané k registraci metod obslužných rutin událostí při spuštění a zastavení aplikace. Rozhraní také obsahuje metodu StopApplication() .

Následující příklad je IHostedService a IHostedLifecycleService implementace, která registruje IHostApplicationLifetime události:

using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace AppLifetime.Example;

public sealed class ExampleHostedService : IHostedService, IHostedLifecycleService
{
    private readonly ILogger _logger;

    public ExampleHostedService(
        ILogger<ExampleHostedService> logger,
        IHostApplicationLifetime appLifetime)
    {
        _logger = logger;

        appLifetime.ApplicationStarted.Register(OnStarted);
        appLifetime.ApplicationStopping.Register(OnStopping);
        appLifetime.ApplicationStopped.Register(OnStopped);
    }

    Task IHostedLifecycleService.StartingAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("1. StartingAsync has been called.");

        return Task.CompletedTask;
    }

    Task IHostedService.StartAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("2. StartAsync has been called.");

        return Task.CompletedTask;
    }

    Task IHostedLifecycleService.StartedAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("3. StartedAsync has been called.");

        return Task.CompletedTask;
    }

    private void OnStarted()
    {
        _logger.LogInformation("4. OnStarted has been called.");
    }

    private void OnStopping()
    {
        _logger.LogInformation("5. OnStopping has been called.");
    }

    Task IHostedLifecycleService.StoppingAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("6. StoppingAsync has been called.");

        return Task.CompletedTask;
    }

    Task IHostedService.StopAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("7. StopAsync has been called.");

        return Task.CompletedTask;
    }

    Task IHostedLifecycleService.StoppedAsync(CancellationToken cancellationToken)
    {
        _logger.LogInformation("8. StoppedAsync has been called.");

        return Task.CompletedTask;
    }

    private void OnStopped()
    {
        _logger.LogInformation("9. OnStopped has been called.");
    }
}

Šablonu pracovní služby je možné upravit tak, aby se přidala ExampleHostedService implementace:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using AppLifetime.Example;

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

builder.Services.AddHostedService<ExampleHostedService>();
using IHost host = builder.Build();

await host.RunAsync();

Aplikace by napsala následující ukázkový výstup:

// Sample output:
//     info: AppLifetime.Example.ExampleHostedService[0]
//           1.StartingAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           2.StartAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           3.StartedAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           4.OnStarted has been called.
//     info: Microsoft.Hosting.Lifetime[0]
//           Application started. Press Ctrl+C to shut down.
//     info: Microsoft.Hosting.Lifetime[0]
//           Hosting environment: Production
//     info: Microsoft.Hosting.Lifetime[0]
//           Content root path: ..\app-lifetime\bin\Debug\net8.0
//     info: AppLifetime.Example.ExampleHostedService[0]
//           5.OnStopping has been called.
//     info: Microsoft.Hosting.Lifetime[0]
//           Application is shutting down...
//     info: AppLifetime.Example.ExampleHostedService[0]
//           6.StoppingAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           7.StopAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           8.StoppedAsync has been called.
//     info: AppLifetime.Example.ExampleHostedService[0]
//           9.OnStopped has been called.

Výstup zobrazuje pořadí všech různých událostí životního cyklu:

  1. IHostedLifecycleService.StartingAsync
  2. IHostedService.StartAsync
  3. IHostedLifecycleService.StartedAsync
  4. IHostApplicationLifetime.ApplicationStarted

Když je aplikace zastavena, například s Ctrl+C, jsou vyvolány následující události:

  1. IHostApplicationLifetime.ApplicationStopping
  2. IHostedLifecycleService.StoppingAsync
  3. IHostedService.StopAsync
  4. IHostedLifecycleService.StoppedAsync
  5. IHostApplicationLifetime.ApplicationStopped

IHostLifetime

Implementace IHostLifetime řídí, kdy se host spustí a kdy se zastaví. Použije se poslední zaregistrovaná implementace. Microsoft.Extensions.Hosting.Internal.ConsoleLifetime je výchozí IHostLifetime implementace. Další informace o mechanice životního cyklu vypnutí najdete v části Vypnutí hostitele.

Rozhraní IHostLifetime zveřejňuje metodu IHostLifetime.WaitForStartAsync, která je volána na začátku IHost.StartAsync a počká na dokončení, než bude pokračovat. Tuto možnost lze použít ke zpoždění spuštění, dokud nebude signalizováno externí událostí.

Kromě toho rozhraní zveřejňuje metodu IHostLifetime, která je volána z IHostLifetime.StopAsync a indikuje, že hostitel se zastavuje a je čas se vypnout.

IHostEnvironment

IHostEnvironment Vložte službu do třídy, abyste získali informace o následujících nastaveních:

Kromě toho IHostEnvironment služba zpřístupňuje možnost vyhodnotit prostředí pomocí těchto rozšiřujících metod:

Konfigurace hostitele

Konfigurace hostitele slouží ke konfiguraci vlastností implementace IHostEnvironment .

Konfigurace hostitele je k dispozici ve HostApplicationBuilderSettings.Configuration vlastnosti a implementace prostředí je k dispozici ve IHostApplicationBuilder.Environment vlastnosti. Pokud chcete hostitele nakonfigurovat, přistupte k Configuration vlastnosti a volejte libovolnou z dostupných metod rozšíření.

Pokud chcete přidat konfiguraci hostitele, zvažte následující příklad:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

HostApplicationBuilderSettings settings = new()
{
    Args = args,
    Configuration = new ConfigurationManager(),
    ContentRootPath = Directory.GetCurrentDirectory(),
};

settings.Configuration.AddJsonFile("hostsettings.json", optional: true);
settings.Configuration.AddEnvironmentVariables(prefix: "PREFIX_");
settings.Configuration.AddCommandLine(args);

HostApplicationBuilder builder = Host.CreateApplicationBuilder(settings);

using IHost host = builder.Build();

// Application code should start here.

await host.RunAsync();

Předchozí kód:

  • Nastaví kořen obsahu na cestu vrácenou GetCurrentDirectory().
  • Načte konfiguraci hostitele z:
    • hostsettings.json.
    • Proměnné prostředí s předponou PREFIX_.
    • Argumenty příkazového řádku

Konfigurace aplikace

Ke konfiguraci aplikace se přistupuje prostřednictvím veřejné IHostApplicationBuilder.Configuration vlastnosti. Tato vlastnost umožňuje uživatelům číst nebo provádět změny stávající konfigurace pomocí dostupných metod rozšíření.

Další informace naleznete v tématu Konfigurace v .NET.

Vypnutí hostitele

Hostovaný proces je zastavený několika způsoby. Hostovaný proces je nejčastěji možné zastavit následujícími způsoby:

Kód hostování neodpovídá za zpracování těchto scénářů. Vlastník procesu se s nimi musí vypořádat stejně jako s jakoukoli jinou aplikací. Proces hostované služby se dá zastavit několika dalšími způsoby:

  • Pokud se použije ConsoleLifetime (UseConsoleLifetime), naslouchá následujícím signálům a pokusí se hostitele zastavit elegantním způsobem.
    • SIGINT (nebo Ctrl+C).
    • SIGQUIT (nebo Ctrl+BREAK ve Windows, Ctrl+\ v Unix).
    • SIGTERM (odesílaný jinými aplikacemi, například docker stop).
  • Pokud aplikace volá Environment.Exit.

Integrovaná logika hostování zpracovává tyto scénáře, konkrétně ConsoleLifetime třídu. ConsoleLifetime se pokusí zpracovat signály "shutdown" SIGINT, SIGQUIT a SIGTERM, aby umožnil řádné ukončení aplikace.

Před .NET 6 neexistuje způsob, jak kód .NET elegantně zpracovat SIGTERM. Aby se toto omezení obešlo, ConsoleLifetime by se přihlásil k odběru System.AppDomain.ProcessExit. Když ProcessExit byl vyvolán, ConsoleLifetime signalizoval hostiteli, aby zastavil a zablokoval ProcessExit vlákno, a čekal, až hostitel zastaví.

Obslužná rutina ukončení procesu by umožnila spuštění vyčišťovacího kódu v aplikaci – například kód před IHost.StopAsync a kód po IHost.StopAsync v metodě Main.

Tento přístup ale měl i jiné problémy, protože SIGTERM nebyl jediným způsobem, jakým bylo ProcessExit vyvoláno. SIGTERM je vyvolán také při volání Environment.Exit kódu aplikace. Environment.Exit není elegantní způsob vypnutí procesu v Microsoft.Extensions.Hosting modelu aplikace. ProcessExit Vyvolá událost a pak proces ukončí. Konec metody Main se neprovede. Vlákna na pozadí a popředí jsou ukončena, a bloky finally se neprovedou.

Vzhledem k tomu, že ConsoleLifetime blokuje ProcessExit při čekání na vypnutí hostitele, toto chování vedlo k zacyklení, protože Environment.Exit také blokuje při čekání na volání ProcessExit. Kromě toho, jelikož se zpracování SIGTERM pokoušelo řádně vypnout proces, ConsoleLifetime nastavil ExitCode na 0, což přepsalo ukončovací kód uživatele předanýEnvironment.Exit.

V rozhraní .NET 6 se podporují a zpracovávají signály POSIX. Rutina ConsoleLifetime elegantně zpracovává SIGTERM a již se neúčastní, když je Environment.Exit vyvolán.

Návod

Pro .NET 6 nebo novější ConsoleLifetime už nemá logiku pro zpracování scénáře Environment.Exit. Aplikace, které volají Environment.Exit a potřebují provádět úklidovou logiku, se mohou sami přihlásit k ProcessExit. Hostitelský systém se už nebude pokoušet o klidné zastavení hostitele v těchto scénářích.

Pokud vaše aplikace používá hostování a chcete elegantně zastavit hostitele, můžete volat IHostApplicationLifetime.StopApplication místo Environment.Exit.

Proces vypnutí hostování

Následující sekvenční diagram ukazuje, jak se signály zpracovávají interně v hostitelském kódu. Většina uživatelů nemusí tomuto procesu rozumět. Ale pro vývojáře, kteří potřebují hluboké porozumění, vám může dobrý vizuál pomoct začít.

Po spuštění hostitele, když uživatel zavolá Run nebo WaitForShutdown, se pro IApplicationLifetime.ApplicationStopping zaregistruje obslužná rutina. Provádění je pozastaveno v WaitForShutdown a čeká na vyvolání události ApplicationStopping. Metoda Main se okamžitě nevrátí a aplikace zůstane spuštěná, dokud Run se nevrátí nebo WaitForShutdown nevrátí.

Když se do procesu odešle signál, zahájí následující sekvenci:

Sekvenční diagram vypnutí hostingu

  1. Řízení proudí z ConsoleLifetime do ApplicationLifetime ke spuštění ApplicationStopping události. To signalizuje WaitForShutdownAsync odblokování spouštěcího Main kódu. Mezitím se obslužná rutina signálu POSIX vrátí s Cancel = true poté, co byl zpracován signál POSIX.
  2. Main kód se znovu spustí a oznámí hostiteli StopAsync(), což následně zastaví všechny hostované služby a aktivuje všechny ostatní události, které byly zastaveny.
  3. Nakonec se ukončí, WaitForShutdown což umožní, aby se jakýkoli kód pro vyčištění aplikace spustil, a Main aby metoda mohla elegantně ukončit.

Vypnutí hostitele ve scénářích webového serveru

Existují různé běžné scénáře, kdy řádné vypnutí funguje v Kestrel pro protokoly HTTP/1.1 i HTTP/2 a jak ho můžete nakonfigurovat v různých prostředích pomocí nástroje pro vyrovnávání zatížení, aby se provoz vyprázdnil hladce. I když konfigurace webového serveru přesahuje rozsah tohoto článku, najdete další informace o konfiguraci možností pro dokumentaci k webovému serveru ASP.NET Core Kestrel.

Když hostitel obdrží signál vypnutí (například Ctrl+C nebo StopAsync), upozorní aplikaci signálem ApplicationStopping. Pokud máte nějaké dlouhotrvající operace, které je potřeba řádně dokončit, měli byste se přihlásit k odběru této události.

Dále hostitel volá IServer.StopAsync s časovým limitem vypnutí, který můžete nakonfigurovat (výchozí 30 s). Kestrel i Http.Sys zavřou svá portová propojení a přestanou přijímat nová připojení. Sdělí také aktuálním připojením, aby přestaly zpracovávat nové požadavky. V případě HTTP/2 a HTTP/3 se klientovi odešle předběžná GOAWAY zpráva. U protokolu HTTP/1.1 zastaví smyčku připojení, protože požadavky se zpracovávají v pořadí. Služba IIS se chová odlišně tím, že odmítne nové požadavky se stavovým kódem 503.

Aktivní požadavky mají čas na dokončení až do vypršení časového limitu vypnutí systému. Pokud jsou všechny dokončeny před vypršením časového limitu, server vrátí řízení hostiteli dříve. Pokud vyprší časový limit, čekající připojení a požadavky jsou vynuceně přerušeny, což může způsobit chyby v protokolech a klientech.

Důležité informace o nástroji pro vyrovnávání zatížení

Pokud chcete zajistit hladký přechod klientů do nového cíle při práci s nástrojem pro vyrovnávání zatížení, můžete postupovat takto:

  • Vyvolání nové instance a zahájení vyrovnávání provozu (pro účely škálování už můžete mít několik instancí).
  • Zakažte nebo odeberte starou instanci v konfiguraci nástroje pro vyrovnávání zatížení, aby přestal přijímat nový provoz.
  • Signalizujte staré instanci, aby se vypnula.
  • Počkejte, až se vyprázdní nebo vyprší časový limit.

Viz také