ASP.NET Core 應(yīng)用配置和啟動(dòng)主機(jī)。 主機(jī)負(fù)責(zé)應(yīng)用程序啟動(dòng)和生存期管理。
本文介紹 ASP.NET Core 泛型主機(jī) (HostBuilder),該主機(jī)用于無(wú)法處理 HTTP 請(qǐng)求的應(yīng)用。
泛型主機(jī)的用途是將 HTTP 管道從 Web 主機(jī) API 中分離出來(lái),從而啟用更多的主機(jī)方案。 基于泛型主機(jī)的消息、后臺(tái)任務(wù)和其他非 HTTP 工作負(fù)載可從橫切功能(如配置、依賴關(guān)系注入 [DI] 和日志記錄)中受益。
泛型主機(jī)是 ASP.NET Core 2.1 中的新增功能,不適用于 Web 承載方案。 對(duì)于 Web 承載方案,請(qǐng)使用 Web 主機(jī)。 泛型主機(jī)將在未來(lái)版本中替換 Web 主機(jī),并在 HTTP 和非 HTTP 方案中充當(dāng)主要的主機(jī) API。
在 Visual Studio Code 中運(yùn)行示例應(yīng)用時(shí),請(qǐng)使用外部或集成終端。 請(qǐng)勿在 internalConsole 中運(yùn)行示例。
在 Visual Studio Code 中設(shè)置控制臺(tái):
通用主機(jī)庫(kù)位于 Microsoft.Extensions.Hosting 命名空間中,由 Microsoft.Extensions.Hosting 包提供。 Microsoft.AspNetCore.App 元包(ASP.NET Core 2.1 或更高版本)中包括 Microsoft.Extensions.Hosting 包。
IHostedService 是執(zhí)行代碼的入口點(diǎn)。 每個(gè) IHostedService 實(shí)現(xiàn)都按照 ConfigureServices 中服務(wù)注冊(cè)的順序執(zhí)行。 主機(jī)啟動(dòng)時(shí),每個(gè) IHostedService 上都會(huì)調(diào)用 StartAsync,主機(jī)正常關(guān)閉時(shí),以反向注冊(cè)順序調(diào)用 StopAsync。
IHostBuilder 是供庫(kù)和應(yīng)用初始化、生成和運(yùn)行主機(jī)的主要組件:
C#
public static async Task Main(string[] args)
{
var host = new HostBuilder()
.Build();
await host.RunAsync();
}
HostOptions 配置 IHost 的選項(xiàng)。
ShutdownTimeout 設(shè)置 StopAsync 的超時(shí)值。 默認(rèn)值為 5 秒。
Program.Main 中的以下選項(xiàng)配置將默認(rèn)值為 5 秒的關(guān)閉超時(shí)值增加至 20 秒:
C#
var host = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
services.Configure<HostOptions>(option =>
{
option.ShutdownTimeout = System.TimeSpan.FromSeconds(20);
});
})
.Build();
在主機(jī)初始化期間注冊(cè)以下服務(wù):
主機(jī)配置的創(chuàng)建方式如下:
IHostingEnvironment.ApplicationName 屬性是在主機(jī)構(gòu)造期間通過(guò)主機(jī)配置設(shè)定的。 要顯式設(shè)置值,請(qǐng)使用 HostDefaults.ApplicationKey:
密鑰:applicationName類型:string默認(rèn)值:包含應(yīng)用入口點(diǎn)的程序集的名稱。設(shè)置使用:HostBuilderContext.HostingEnvironment.ApplicationName環(huán)境變量:<PREFIX_>APPLICATIONNAME(<PREFIX_> 是用戶定義的可選前綴)
此設(shè)置確定主機(jī)從哪里開(kāi)始搜索內(nèi)容文件。
鍵:contentRoot類型:string默認(rèn)值:默認(rèn)為應(yīng)用程序集所在的文件夾。設(shè)置使用:UseContentRoot環(huán)境變量:<PREFIX_>CONTENTROOT(<PREFIX_> 是用戶定義的可選前綴)
如果路徑不存在,主機(jī)將無(wú)法啟動(dòng)。
C#
var host = new HostBuilder()
.UseContentRoot("c:\\<content-root>")
設(shè)置應(yīng)用的環(huán)境。
鍵:環(huán)境類型:string默認(rèn)值:生產(chǎn)設(shè)置使用:UseEnvironment環(huán)境變量:<PREFIX_>ENVIRONMENT(<PREFIX_> 是用戶定義的可選前綴)
環(huán)境可以設(shè)置為任何值。 框架定義的值包括 Development``Staging 和 Production。 值不區(qū)分大小寫。
C#
var host = new HostBuilder()
.UseEnvironment(EnvironmentName.Development)
ConfigureHostConfiguration 使用 IConfigurationBuilder 來(lái)為主機(jī)創(chuàng)建 IConfiguration。 主機(jī)配置用于初始化 IHostingEnvironment,以供在應(yīng)用的構(gòu)建過(guò)程中使用。
可多次調(diào)用 ConfigureHostConfiguration,并得到累計(jì)結(jié)果。 主機(jī)使用上一次在一個(gè)給定鍵上設(shè)置值的選項(xiàng)。
主機(jī)配置自動(dòng)流向應(yīng)用配置(ConfigureAppConfiguration 和應(yīng)用的其余部分)。
默認(rèn)情況下不包括提供程序。 必須在 ConfigureHostConfiguration 中顯式指定應(yīng)用所需的任何配置提供程序,包括:
通過(guò)使用 SetBasePath 指定應(yīng)用的基本路徑,然后調(diào)用其中一個(gè)文件配置提供程序,可以啟用主機(jī)的文件配置。 示例應(yīng)用使用 JSON 文件 hostsettings.json,并調(diào)用 AddJsonFile 來(lái)使用文件的主機(jī)配置設(shè)置。
要添加主機(jī)的環(huán)境變量配置,請(qǐng)?jiān)谥鳈C(jī)生成器上調(diào)用 AddEnvironmentVariables。 AddEnvironmentVariables 接受用戶定義的前綴(可選)。 示例應(yīng)用使用前綴 PREFIX_。 當(dāng)系統(tǒng)讀取環(huán)境變量時(shí),便會(huì)刪除前綴。 配置示例應(yīng)用的主機(jī)后,PREFIX_ENVIRONMENT 的環(huán)境變量值就變成 environment 密鑰的主機(jī)配置值。
在開(kāi)發(fā)過(guò)程中,如果使用 Visual Studio 或通過(guò) dotnet run 運(yùn)行應(yīng)用,可能會(huì)在 Properties/launchSettings.json 文件中設(shè)置環(huán)境變量。 若在開(kāi)發(fā)過(guò)程中使用 Visual Studio Code,可能會(huì)在 .vscode/launch.json 文件中設(shè)置環(huán)境變量。 有關(guān)更多信息,請(qǐng)參見(jiàn)在 ASP.NET Core 中使用多個(gè)環(huán)境。
通過(guò)調(diào)用 AddCommandLine 可添加命令行配置。 最后添加命令行配置以允許命令行參數(shù)替代之前配置提供程序提供的配置。
hostsettings.json:
C#
{
"environment": "Development"
}
可以通過(guò) applicationName 和 contentRoot 鍵提供其他配置。
示例 HostBuilder 配置使用 ConfigureHostConfiguration:
C#
var host = new HostBuilder()
.ConfigureHostConfiguration(configHost =>
{
configHost.SetBasePath(Directory.GetCurrentDirectory());
configHost.AddJsonFile("hostsettings.json", optional: true);
configHost.AddEnvironmentVariables(prefix: "PREFIX_");
configHost.AddCommandLine(args);
})
通過(guò)在 IHostBuilder 實(shí)現(xiàn)上調(diào)用 ConfigureAppConfiguration 創(chuàng)建應(yīng)用配置。ConfigureAppConfiguration 使用 IConfigurationBuilder 來(lái)為應(yīng)用創(chuàng)建 IConfiguration。 可多次調(diào)用 ConfigureAppConfiguration,并得到累計(jì)結(jié)果。 應(yīng)用使用上一次在一個(gè)給定鍵上設(shè)置值的選項(xiàng)。HostBuilderContext.Configuration 中提供 ConfigureAppConfiguration 創(chuàng)建的配置,以供進(jìn)行后續(xù)操作和在 Services 中使用。
應(yīng)用配置會(huì)自動(dòng)接收 ConfigureHostConfiguration 提供的主機(jī)配置。
示例應(yīng)用配置使用 ConfigureAppConfiguration:
C#
var host = new HostBuilder()
.ConfigureAppConfiguration((hostContext, configApp) =>
{
configApp.SetBasePath(Directory.GetCurrentDirectory());
configApp.AddJsonFile("appsettings.json", optional: true);
configApp.AddJsonFile(
$"appsettings.{hostContext.HostingEnvironment.EnvironmentName}.json",
optional: true);
configApp.AddEnvironmentVariables(prefix: "PREFIX_");
configApp.AddCommandLine(args);
})
appsettings.json:
C#
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}
appsettings.Development.json:
C#
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
appsettings.Production.json:
C#
{
"Logging": {
"LogLevel": {
"Default": "Error",
"System": "Information",
"Microsoft": "Information"
}
}
}
要將設(shè)置文件移動(dòng)到輸出目錄,請(qǐng)?jiān)陧?xiàng)目文件中將設(shè)置文件指定為 MSBuild 項(xiàng)目項(xiàng)。 示例應(yīng)用移動(dòng)具有以下 <Content> 項(xiàng)的 JSON 應(yīng)用設(shè)置文件和 hostsettings.json:
XML
<ItemGroup>
<Content Include="**\*.json" Exclude="bin\**\*;obj\**\*"
CopyToOutputDirectory="PreserveNewest" />
</ItemGroup>
ConfigureServices 將服務(wù)添加到應(yīng)用的依賴關(guān)系注入容器。 可多次調(diào)用 ConfigureServices,并得到累計(jì)結(jié)果。
托管服務(wù)是一個(gè)類,具有實(shí)現(xiàn) IHostedService 接口的后臺(tái)任務(wù)邏輯。 有關(guān)更多信息,請(qǐng)參見(jiàn)在 ASP.NET Core 中使用托管服務(wù)實(shí)現(xiàn)后臺(tái)任務(wù)。
示例應(yīng)用使用 AddHostedService 擴(kuò)展方法向應(yīng)用添加生存期事件 LifetimeEventsHostedService 和定時(shí)后臺(tái)任務(wù) TimedHostedService 服務(wù):
C#
var host = new HostBuilder()
.ConfigureServices((hostContext, services) =>
{
if (hostContext.HostingEnvironment.IsDevelopment())
{
// Development service configuration
}
else
{
// Non-development service configuration
}
services.AddHostedService<LifetimeEventsHostedService>();
services.AddHostedService<TimedHostedService>();
})
ConfigureLogging 添加了一個(gè)委托來(lái)配置提供的 ILoggingBuilder。 可以利用相加結(jié)果多次調(diào)用 ConfigureLogging。
C#
var host = new HostBuilder()
.ConfigureLogging((hostContext, configLogging) =>
{
configLogging.AddConsole();
configLogging.AddDebug();
})
UseConsoleLifetime 偵聽(tīng) Ctrl+C/SIGINT 或 SIGTERM 并調(diào)用 StopApplication 來(lái)啟動(dòng)關(guān)閉進(jìn)程。UseConsoleLifetime 解除阻止 RunAsync 和 WaitForShutdownAsync 等擴(kuò)展。 ConsoleLifetime 預(yù)注冊(cè)為默認(rèn)生存期實(shí)現(xiàn)。 使用注冊(cè)的最后一個(gè)生存期。
C#
var host = new HostBuilder()
.UseConsoleLifetime()
為支持插入其他容器中,主機(jī)可以接受 IServiceProviderFactory<TContainerBuilder>。 提供工廠不屬于 DI 容器注冊(cè),而是用于創(chuàng)建具體 DI 容器的主機(jī)內(nèi)部函數(shù)。UseServiceProviderFactory(IServiceProviderFactory<TContainerBuilder>) 重寫用于創(chuàng)建應(yīng)用的服務(wù)提供程序的默認(rèn)工廠。
ConfigureContainer 方法托管自定義容器配置。 ConfigureContainer 提供在基礎(chǔ)主機(jī) API 的基礎(chǔ)之上配置容器的強(qiáng)類型體驗(yàn)。 可以利用相加結(jié)果多次調(diào)用 ConfigureContainer。
為應(yīng)用創(chuàng)建服務(wù)容器:
C#
namespace GenericHostSample
{
internal class ServiceContainer
{
}
}
提供服務(wù)容器工廠:
C#
using System;
using Microsoft.Extensions.DependencyInjection;
namespace GenericHostSample
{
internal class ServiceContainerFactory :
IServiceProviderFactory<ServiceContainer>
{
public ServiceContainer CreateBuilder(
IServiceCollection services)
{
return new ServiceContainer();
}
public IServiceProvider CreateServiceProvider(
ServiceContainer containerBuilder)
{
throw new NotImplementedException();
}
}
}
使用該工廠并為應(yīng)用配置自定義服務(wù)容器:
C#
var host = new HostBuilder()
.UseServiceProviderFactory<ServiceContainer>(new ServiceContainerFactory())
.ConfigureContainer<ServiceContainer>((hostContext, container) =>
{
})
在 IHostBuilder 上使用擴(kuò)展方法實(shí)現(xiàn)主機(jī)擴(kuò)展性。 以下示例介紹擴(kuò)展方法如何使用 在 ASP.NET Core 中使用托管服務(wù)實(shí)現(xiàn)后臺(tái)任務(wù) 中所示的 TimedHostedService 示例來(lái)擴(kuò)展 IHostBuilder 實(shí)現(xiàn)。
C#
var host = new HostBuilder()
.UseHostedService<TimedHostedService>()
.Build();
await host.StartAsync();
應(yīng)用建立 UseHostedService 擴(kuò)展方法,以注冊(cè)在 T 中傳遞的托管服務(wù):
C#
using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
public static class Extensions
{
public static IHostBuilder UseHostedService<T>(this IHostBuilder hostBuilder)
where T : class, IHostedService, IDisposable
{
return hostBuilder.ConfigureServices(services =>
services.AddHostedService<T>());
}
}
IHost 實(shí)現(xiàn)負(fù)責(zé)啟動(dòng)和停止服務(wù)容器中注冊(cè)的 IHostedService 實(shí)現(xiàn)。
Run 運(yùn)行應(yīng)用并阻止調(diào)用線程,直到關(guān)閉主機(jī):
C#
public class Program
{
public void Main(string[] args)
{
var host = new HostBuilder()
.Build();
host.Run();
}
}
RunAsync 運(yùn)行應(yīng)用并返回在觸發(fā)取消令牌或關(guān)閉時(shí)完成的 Task:
C#
public class Program
{
public static async Task Main(string[] args)
{
var host = new HostBuilder()
.Build();
await host.RunAsync();
}
}
RunConsoleAsync 啟用控制臺(tái)支持、生成和啟動(dòng)主機(jī),以及等待 Ctrl+C/SIGINT 或 SIGTERM 關(guān)閉。
C#
public class Program
{
public static async Task Main(string[] args)
{
var hostBuilder = new HostBuilder();
await hostBuilder.RunConsoleAsync();
}
}
Start 同步啟動(dòng)主機(jī)。
StopAsync 嘗試在提供的超時(shí)時(shí)間內(nèi)停止主機(jī)。
C#
public class Program
{
public static async Task Main(string[] args)
{
var host = new HostBuilder()
.Build();
using (host)
{
host.Start();
await host.StopAsync(TimeSpan.FromSeconds(5));
}
}
}
StartAsync 啟動(dòng)應(yīng)用。
StopAsync 停止應(yīng)用。
C#
public class Program
{
public static async Task Main(string[] args)
{
var host = new HostBuilder()
.Build();
using (host)
{
await host.StartAsync();
await host.StopAsync();
}
}
}
WaitForShutdown 通過(guò) IHostLifetime 觸發(fā),例如 ConsoleLifetime(偵聽(tīng) Ctrl+C/SIGINT 或 SIGTERM)。 WaitForShutdown 調(diào)用 StopAsync。
C#
public class Program
{
public void Main(string[] args)
{
var host = new HostBuilder()
.Build();
using (host)
{
host.Start();
host.WaitForShutdown();
}
}
}
WaitForShutdownAsync 返回在通過(guò)給定的令牌和調(diào)用 StopAsync 來(lái)觸發(fā)關(guān)閉時(shí)完成的 Task。
C#
public class Program
{
public static async Task Main(string[] args)
{
var host = new HostBuilder()
.Build();
using (host)
{
await host.StartAsync();
await host.WaitForShutdownAsync();
}
}
}
使用可從外部調(diào)用的方法,能夠?qū)崿F(xiàn)主機(jī)的外部控件:
C#
public class Program
{
private IHost _host;
public Program()
{
_host = new HostBuilder()
.Build();
}
public async Task StartAsync()
{
_host.StartAsync();
}
public async Task StopAsync()
{
using (_host)
{
await _host.StopAsync(TimeSpan.FromSeconds(5));
}
}
}
在 StartAsync 開(kāi)始時(shí)調(diào)用 WaitForStartAsync,在繼續(xù)之前,會(huì)一直等待該操作完成。 它可用于延遲啟動(dòng),直到外部事件發(fā)出信號(hào)。
IHostingEnvironment 提供有關(guān)應(yīng)用托管環(huán)境的信息。 使用構(gòu)造函數(shù)注入獲取 IHostingEnvironment以使用其屬性和擴(kuò)展方法:
C#
public class MyClass
{
private readonly IHostingEnvironment _env;
public MyClass(IHostingEnvironment env)
{
_env = env;
}
public void DoSomething()
{
var environmentName = _env.EnvironmentName;
}
}
有關(guān)更多信息,請(qǐng)參見(jiàn)在 ASP.NET Core 中使用多個(gè)環(huán)境。
IApplicationLifetime 允許啟動(dòng)后和關(guān)閉活動(dòng),包括正常關(guān)閉請(qǐng)求。 接口上的三個(gè)屬性是用于注冊(cè) Action 方法(用于定義啟動(dòng)和關(guān)閉事件)的取消標(biāo)記。
取消標(biāo)記 | 觸發(fā)條件 |
---|---|
ApplicationStarted | 主機(jī)已完全啟動(dòng)。 |
ApplicationStopped | 主機(jī)正在完成正常關(guān)閉。 應(yīng)處理所有請(qǐng)求。 關(guān)閉受到阻止,直到完成此事件。 |
ApplicationStopping | 主機(jī)正在執(zhí)行正常關(guān)閉。 仍在處理請(qǐng)求。 關(guān)閉受到阻止,直到完成此事件。 |
構(gòu)造函數(shù)將 IApplicationLifetime 服務(wù)注入到任何類中。 示例應(yīng)用將構(gòu)造函數(shù)注入到 LifetimeEventsHostedService 類(一個(gè) IHostedService 實(shí)現(xiàn))中,用于注冊(cè)事件。
LifetimeEventsHostedService.cs:
C#
internal class LifetimeEventsHostedService : IHostedService
{
private readonly ILogger _logger;
private readonly IApplicationLifetime _appLifetime;
public LifetimeEventsHostedService(
ILogger<LifetimeEventsHostedService> logger,
IApplicationLifetime appLifetime)
{
_logger = logger;
_appLifetime = appLifetime;
}
public Task StartAsync(CancellationToken cancellationToken)
{
_appLifetime.ApplicationStarted.Register(OnStarted);
_appLifetime.ApplicationStopping.Register(OnStopping);
_appLifetime.ApplicationStopped.Register(OnStopped);
return Task.CompletedTask;
}
public Task StopAsync(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
private void OnStarted()
{
_logger.LogInformation("OnStarted has been called.");
// Perform post-startup activities here
}
private void OnStopping()
{
_logger.LogInformation("OnStopping has been called.");
// Perform on-stopping activities here
}
private void OnStopped()
{
_logger.LogInformation("OnStopped has been called.");
// Perform post-stopped activities here
}
}
StopApplication 請(qǐng)求終止應(yīng)用。 以下類在調(diào)用類的 Shutdown 方法時(shí)使用 StopApplication 正常關(guān)閉應(yīng)用:
C#
public class MyClass
{
private readonly IApplicationLifetime _appLifetime;
public MyClass(IApplicationLifetime appLifetime)
{
_appLifetime = appLifetime;
}
public void Shutdown()
{
_appLifetime.StopApplication();
}
}
更多建議: