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 . Obecný hostitel .NET zodpovídá za správu po spuštění a životnosti 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 životnost 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í.
Nastavení hostitele
Hostitel je obvykle nakonfigurovaný, sestavený a spouštěný kódem ve Program
třídě. Metoda Main
:
- Volá metodu CreateApplicationBuilder pro vytvoření a konfiguraci objektu tvůrce.
- Volání Build() k vytvoření IHost instance.
- Volá Run nebo RunAsync metodu objektu hostitele.
Š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í tvůrce hostitelů
Metoda CreateApplicationBuilder:
- Nastaví kořen obsahu na cestu vrácenou .GetCurrentDirectory()
- Načte konfiguraci hostitele z:
- Proměnné prostředí s předponou
DOTNET_
. - Argumenty příkazového řádku
- Proměnné prostředí s předponou
- 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í
- EventSource
- EventLog (pouze při spuštění ve Windows)
- Povolí ověřování oboru a ověřování závislostí, pokud je
Development
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é architekturou
Při volání nebo IHostBuilder.Build()HostApplicationBuilder.Build()se automaticky zaregistrují následující služby:
Další tvůrci hostitelů založených na scénářích
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ů:
- DistributedApplicationBuilder: Tvůrce pro vytváření distribuovaných aplikací. Další informace naleznete v tématu .NET Aspire.
- WebApplicationBuilder: Tvůrce webových aplikací a služeb. Další informace najdete v tématu ASP.NET Core.
-
WebHostBuilder: Tvůrce pro
IWebHost
. Další informace najdete v tématu ASP.NET webového hostitele Core.
IHostApplicationLifetime
IHostApplicationLifetime Vložte službu do libovolné třídy pro zpracování úloh po spuštění a řádném vypnutí. Tři vlastnosti rozhraní jsou tokeny zrušení používané k registraci metod spuštění aplikace a zastavení aplikace obslužné rutiny událostí. 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:
IHostedLifecycleService.StartingAsync
IHostedService.StartAsync
IHostedLifecycleService.StartedAsync
IHostApplicationLifetime.ApplicationStarted
Když je aplikace zastavena, například s Ctrl+C, jsou vyvolány následující události:
IHostApplicationLifetime.ApplicationStopping
IHostedLifecycleService.StoppingAsync
IHostedService.StopAsync
IHostedLifecycleService.StoppedAsync
IHostApplicationLifetime.ApplicationStopped
IHostLifetime
Implementace IHostLifetime řídí, kdy se hostitel spustí a kdy se zastaví. Použije se poslední zaregistrovaná implementace.
Microsoft.Extensions.Hosting.Internal.ConsoleLifetime
je výchozí IHostLifetime
implementace. Další informace o mechanismu životnosti vypnutí najdete v tématu Vypnutí hostitele.
Rozhraní IHostLifetime
zveřejňuje metodu IHostLifetime.WaitForStartAsync , která je volána na začátku IHost.StartAsync
, která bude čekat na dokončení, než bude pokračovat. Tuto možnost lze použít ke zpoždění spouštění, dokud není signalizovat externí událostí.
Kromě toho rozhraní zveřejňuje metoduIHostLifetime
, která je volána z IHostLifetime.StopAsync indikující, IHost.StopAsync
že hostitel se zastavuje a je čas vypnout.
IHostEnvironment
IHostEnvironment Vložte službu do třídy, abyste získali informace o následujících nastaveních:
- IHostEnvironment.ApplicationName
- IHostEnvironment.ContentRootFileProvider
- IHostEnvironment.ContentRootPath
- IHostEnvironment.EnvironmentName
Kromě toho IHostEnvironment
služba zpřístupňuje možnost vyhodnotit prostředí pomocí těchto rozšiřujících metod:
- HostingEnvironmentExtensions.IsDevelopment
- HostingEnvironmentExtensions.IsEnvironment
- HostingEnvironmentExtensions.IsProduction
- HostingEnvironmentExtensions.IsStaging
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, získejte přístup k Configuration
vlastnosti a volejte některou 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
Konfigurace aplikace se vytvoří voláním ConfigureAppConfiguration na .IHostApplicationBuilder Veřejná IHostApplicationBuilder.Configuration 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:
- Pokud někdo nezavolá Run nebo HostingAbstractionsHostExtensions.WaitForShutdown se aplikace normálně ukončí s dokončením
Main
. - Pokud se aplikace chybově ukončí.
- Pokud je aplikace vynuceně vypnuta pomocí SIGKILL (nebo Ctrl+Z).
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
ConsoleLifetime
se použije (UseConsoleLifetime), naslouchá následujícím signálům a pokusí se hostiteli elegantně zastavit. - Pokud aplikace volá Environment.Exit.
Integrovaná logika hostování zpracovává tyto scénáře, konkrétně ConsoleLifetime
třídu.
ConsoleLifetime
se pokusí zpracovat "vypnutí" signály SIGINT, SIGQUIT a SIGTERM, aby umožňovaly řádné ukončení aplikace.
Před .NET 6 neexistuje způsob, jak kód .NET elegantně zpracovat SIGTERM. Pokud chcete toto omezení obejít, ConsoleLifetime
přihlaste se k odběru System.AppDomain.ProcessExit. Když ProcessExit
byl vyvolán, ConsoleLifetime
signalizoval by hostitel, aby zastavil a zablokoval ProcessExit
vlákno, a čekal na zastavení hostitele.
Obslužná rutina ukončení procesu by umožňovala spuštění kódu vyčištění v aplikaci – IHost.StopAsync například kód za HostingAbstractionsHostExtensions.Run metodou Main
.
Tento přístup ale měl i jiné problémy, protože SIGTERM nebyl jediným způsobem ProcessExit
. 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 Main
metody se nespustí. Vlákna na pozadí a popředí jsou ukončena a finally
bloky se nespustí .
Vzhledem k tomu, ConsoleLifetime
že blokované ProcessExit
při čekání na vypnutí hostitele, toto chování vedlo k zablokování z Environment.Exit
také bloků čekání na volání ProcessExit
. Kromě toho, že se zpracování SIGTERM pokoušelo řádně vypnout proces, ConsoleLifetime
by nastavil ExitCode na 0
, který zahltí ukončovací kód uživatele předanýEnvironment.Exit
.
V rozhraní .NET 6 se podporují a zpracovávají signály POSIX. Obslužné ConsoleLifetime
rutiny SIGTERM elegantně a při vyvolání se už nezabývá Environment.Exit
.
Tip
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 logiku čištění, se můžou přihlásit k odběru ProcessExit
sebe sama. Hostování se už nebude pokoušet o řádné 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 hostování vypnutí
Následující sekvenční diagram ukazuje, jak se signály zpracovávají interně v hostitelském kódu. Většinauživatelůch 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 se při volání Run
uživatele nebo WaitForShutdown
obslužné rutině zaregistruje IApplicationLifetime.ApplicationStopping. Provádění je pozastaveno v WaitForShutdown
, čeká ApplicationStopping
na vyvolání události. 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:
- Řízení proudí z
ConsoleLifetime
dosadíApplicationLifetime
ApplicationStopping
událost. To signalizujeWaitForShutdownAsync
odblokování spouštěcíhoMain
kódu. Mezitím se obslužná rutina signálu POSIX vrátí odCancel = true
doby, kdy byl zpracován signál POSIX. - Spouštěcí
Main
kód se spustí znovu a řekne hostiteli, kterémuStopAsync()
se zase zastaví všechny hostované služby a vyvolá všechny ostatní zastavené události. - Nakonec se ukončí,
WaitForShutdown
což umožní, aby se jakýkoli kód pro vyčištění aplikace spustil, aMain
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 volání IServer.StopAsync hostitele s vypršením časového limitu vypnutí, který můžete nakonfigurovat (výchozí 30s). Kestrel (a Http.Sys) zavře své vazby portů a přestane přijímat nová připojení. Sdělí také aktuálním připojením, aby přestala 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 budou mít do vypršení časového limitu vypnutí. 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.
- Signalizovat starou instanci, aby se vypnula.
- Počkejte, až se vyprázdní nebo vyprší časový limit.
Viz také
- Injektáž závislostí v .NET
- Protokolování v .NET
- Konfigurace v .NET
- Služby pracovních procesů v .NET
- Webový hostitel ASP.NET Core
- konfigurace webového serveru ASP.NET Core Kestrel
- V úložišti github.com/dotnet/runtime by se měly vytvořit obecné chyby hostitele.