.NET 通用主机(Generic Host)
此为系列文章,对MSDN ASP.NET Core 的官方文档进行系统学习与翻译。其中或许会添加本人对 ASP.NET Core 的浅显理解。
这篇文章介绍了.NET Core通用主机,并提供了如何使用它的一些指南。
什么是主机?
主机是封装了app资源的一些对象,比如:
- 依赖注入(DI)
- 日志
- 配置
IHostedService
的实现
当一个主机启动时,它会首先在DI容器中查找所有的IHostedService实现,然后在每个找到的实现上调用它的IHostedService.StartAsync
方法。在一个web app中,IHostedService
的实现之一便是web 服务器,它启动了一个HTTP server implementation。
将所有app需要的资源包含进一个对象的主要原因便是生命周期管理:在app启动时进行控制并优雅地关闭。
在ASP.NET Core 3.0以前的版本中,Web Host被用来做HTTP工作负载。从ASP.NET Core 3.0开始,Web Host不再推荐为web app所用,其现在仅用作向后兼容。
建立一个主机
典型的,一个主机在Program.Main方法里进行配置,建立,运行:
- 调用
CreateHostBuilder
来创建和配置一个建造者对象。 - 在建造者对象上调用Build,Run方法。
这里是一个非HTTP工作负载的Program.cs代码,并且将一个IHostedService
实现添加进DI容器中:
public class Program { public static void Main(string[] args) { CreateHostBuilder(args).Build().Run(); } public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureServices((hostContext, services) => { services.AddHostedService<Worker>(); }); }
对于一个HTTP工作负载,Main方法是相同的,但是CreateHostBuilder
调用了ConfigureWebHostDefaults
:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.UseStartup<Startup>(); });
如果app使用了Entity Framework Core,请不要更改CreateHostBuilder
方法的名称以及签名。Entity Framework Core tools这个工具期望找到一个CreateHostBuilder
方法来配置主机,而不用运行app。更多信息,请参考Design-time DbContext Creation。
默认建造者设置
- 为GetCurrentDirectory方法返回的路径设置内容根。
- 从下列位置加载目录配置:具有“DOTNET_”前缀的环境变量,命令行参数。
- 从下列位置加载app配置:appsettings.json,appsettings.{Environment}.json,当app运行在开发环境中时的Secret Manager,环境变量,命令行参数。
- 添加如下的日志提供器:Console,Debug,EventSource,EventLog(仅当运行在Windows上)。
- 当在开发环境中时,启用域验证以及依赖验证。
ConfigureWebHostDefaults
方法:
- 从具有前缀“ASPNETCORE_”的环境变量中加载主机配置。
- 将Kestrel服务器设置为web服务器,并配置其使用app的主机配置提供器。关于Kestrel服务器的默认选项,请参考Kestrel web server implementation in ASP.NET Core。
- 添加主机过滤中间件(Host Filtering middleware)。
- 如果这个配置ASPNETCORE_FORWARDEDHEADERS_ENABLED=true的话,添加Forwarded Headers middleware。
- 启用IIS集成。了解IIS默认选项,请参考Host ASP.NET Core on Windows with IIS。
本章后续的两个章节Settings for all app types 以及 Settings for web apps 展示了如何重载默认的建造者设置。
框架提供的服务
自动注册的服务包含如下:
关于框架提供的服务的更多信息,请参考Dependency injection in ASP.NET Core。
接口IHostApplicationLifetime
将IHostApplicationLifetime接口注入到任何类以处理启动后(post-startup)以及优雅的关闭这些任务。这个接口的三个属性是用来注册app开始及 停止事件处理方法的取消标记。这个接口也包含了一个StopApplication
方法。
如下示例是一个注册了IHostApplicationLifetime
事件的IHostedService
的实现:
internal class LifetimeEventsHostedService : IHostedService { private readonly ILogger _logger; private readonly IHostApplicationLifetime _appLifetime; public LifetimeEventsHostedService( ILogger<LifetimeEventsHostedService> logger, IHostApplicationLifetime 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 } }
接口IHostLifetime
接口IHostLifetime的实现控制着何时开始主机以及何时关闭主机。最后一个注册的实现将被使用。Microsoft.Extensions.Hosting.Internal.ConsoleLifetime
是默认的IHostLifetime
的实现。ConsoleLifetime
:
- 对Ctrl+C/SIGINT或者SIGTERM进行监听,并调用StopApplication来开始关闭进程。
- 解锁扩展,比如RunAsync 和WaitForShutdownAsync。
接口IHostEnvironment
将IHostEnvironment服务注入到一个类中可以获取下列信息:
web app实现了这个接口,其继承了IHostEnvironment
并添加了WebRootPath。
主机配置
主机配置用作IHostEnvironment实现的属性。
主机配置从在ConfigureAppConfiguration内部的HostBuilderContext.Configuration可用。在ConfigureAppConfiguration
之后,HostBuilderContext.Configuration
便被app.config所代替。
为了添加主机配置,我们可以调用IHostBuilder
的ConfigureHostConfiguration方法。ConfigureHostConfiguration
方法可以被调用多次以产生额外的结果。对于一个给定的值,主机会使用最后一次设置它的值的那个选项。
具有前缀DOTNET_
的环境变量提供器以及命令行参数被包含在CreateDefaultBuilder中。对于web app来说,具有前缀ASPNETCORE_
的环境变量提供器被添加。当读取环境变量时会移除它们的前缀。举个例子,ASPNETCORE_ENVIRONMENT
环境变量值将会变成主机配置值:键environment
。
如下示例创建了主机配置:
// using Microsoft.Extensions.Configuration; Host.CreateDefaultBuilder(args) .ConfigureHostConfiguration(configHost => { configHost.SetBasePath(Directory.GetCurrentDirectory()); configHost.AddJsonFile("hostsettings.json", optional: true); configHost.AddEnvironmentVariables(prefix: "PREFIX_"); configHost.AddCommandLine(args); });
app配置
通过调用IHostBuilder
的ConfigureAppConfiguration来创建app配置。ConfigureAppConfiguration
方法可以被调用多次以产生额外的结果。对于一个给定的值,主机会使用最后一次设置它的值的那个选项。
ConfigureAppConfiguration
创建的配置在HostBuilderContext.Configuration中可用做后续的操作以及作为一个从DI获取的服务,主机配置也被加进app配置中。
更多信息,请参考Configuration in ASP.NET Core。
所有app类型的设置
这个章节列举了应用于HTTP以及非HTTP工作负载的一些主机设置。默认的,用于配置这些设置的环境变量具有DOTNET_
或者ASPNETCORE_
前缀。
ApplicationName
在主机构造时,通过主机配置来设置IHostEnvironment.ApplicationName。
键:applicationName
类型:字符串
默认值:包含了app入口点的程序集的名称。
环境变量:<PREFIX_>APPLICATIONNAME
可以使用环境变量来设置此值。
ContentRootPath
IHostEnvironment.ContentRootPath属性决定了主机从哪儿开始来搜索内容文件。如果路径不存在,那么主机便不会启动。
键:contentRoot
类型:字符串
默认值:app程序集所在的文件夹
环境变量:<PREFIX_>CONTENTROOT
可以使用环境变量或者调用IHostBuilder
的UseContentRoot
来设置此值。
Host.CreateDefaultBuilder(args) .UseContentRoot("c:\\content-root") //...
更多信息,请参考:
ShutdownTimeout
HostOptions.ShutdownTimeout 为StopAsync 方法设置超时时间。默认值是5秒。在超时期间,主机:
- 触发IHostApplicationLifetime.ApplicationStopping。
- 试图停止寄宿的服务,如果一个服务没有成功停止,则为它们记录日志。
如果超时时间在所有的寄宿服务 停止之前过期,任何遗留的活动的服务都会在app关闭时候停止,即使它们还没有结束处理。如果服务需要额外的时间来停止,那么就增加超时时间。
键:shutdownTimeoutSeconds
类型:整型
默认值:5秒
环境变量:<PREFIX_>SHUTDOWNTIMEOUTSECONDS
使用环境变量或者设置HostOptions
来设置此值。下面的示例将超时时间设置为20秒:
Host.CreateDefaultBuilder(args) .ConfigureServices((hostContext, services) => { services.Configure<HostOptions>(option => { option.ShutdownTimeout = System.TimeSpan.FromSeconds(20); }); });
web app的设置
一些主机设置仅仅应用于HTTP工作负载。默认的,用于配置这些设置的环境变量都具有DOTNET_
或者 ASPNETCORE_
前缀。
IWebHostBuilder上的扩展方法对于这些设置是可用的。展示如何调用扩展方法的代码示例假设
webBuilder
是IWebHostBuilder
的一个实例。比如如下代码:
public static IHostBuilder CreateHostBuilder(string[] args) => Host.CreateDefaultBuilder(args) .ConfigureWebHostDefaults(webBuilder => { webBuilder.CaptureStartupErrors(true); webBuilder.UseStartup<Startup>(); });
CaptureStartupErrors
当设置为false时,启动时的错误会导致主机存在。当设置为true时,主机捕获启动时的异常并试图开始服务。
键:captureStartupErrors
类型:布尔
默认值:默认为false,除非app运行在IIS之下的Kestrel中,此时默认值为true。
环境变量:<PREFIX_>CAPTURESTARTUPERRORS
使用配置或者调用CaptureStartupErrors
来设置此值:
webBuilder.CaptureStartupErrors(true);
DetailedErrors
当启用时,或者当环境为开发环境时,app会捕获详细的错误信息。
键:detailedErrors
类型:布尔
默认值:false
环境变量:<PREFIX_>_DETAILEDERRORS
使用配置或者调用UseSetting
来设置此值:
webBuilder.UseSetting(WebHostDefaults.DetailedErrorsKey, "true");
HostStartupAssemblies
主机启动程序集是以分号隔开的,它会在启动的时候被加载。虽然配置值默认为一个空字符串,主机启动程序集总是包含app的程序集。当提供了主机启动程序集时当app在开始阶段构建它的通用服务时,它们会被添加到app的程序集中。
键:hostingStartupAssemblies
类型:字符串
默认值:空字符串
环境变量:<PREFIX_>_HOSTINGSTARTUPASSEMBLIES
使用配置或者调用UseSetting
来设置此值:
webBuilder.UseSetting(WebHostDefaults.HostingStartupAssembliesKey, "assembly1;assembly2");
HostingStartupExcludeAssemblies
在app开始时,被排除的以分号隔开的主机启动程序集。
键:hostingStartupExcludeAssemblies
类型:字符串
默认值:空字符串
环境变量:<PREFIX_>_HOSTINGSTARTUPEXCLUDEASSEMBLIES
使用配置或者调用UseSetting
来设置此值:
webBuilder.UseSetting(WebHostDefaults.HostingStartupExcludeAssembliesKey, "assembly1;assembly2");
HTTPS_Port
HTTPS重定向端口。使用在enforcing HTTPS之中。
键:https_port
类型:字符串
默认值:无默认值
环境变量:<PREFIX_>HTTPS_PORT
使用配置或者调用UseSetting
来设置此值:
webBuilder.UseSetting("https_port", "8080");
PreferHostingUrls
指示主机是否要监听使用IWebHostBuilder
配置的URLs,而不是使用IServer
实现配置的URLs.
键:preferHostingUrls
类型:布尔
默认值:true
环境变量:<PREFIX_>_PREFERHOSTINGURLS
使用配置或者调用PreferHostingUrls
来设置此值:
webBuilder.PreferHostingUrls(false);
PreventHostingStartup
阻止主机启动程序的自动加载,包括由app的程序集配置的主机启动程序集。更多信息,请参考Use hosting startup assemblies in ASP.NET Core。
键:preventHostingStartup
类型:布尔
默认值:false
环境变量:<PREFIX_>_PREVENTHOSTINGSTARTUP
使用配置或者调用UseSetting
来设置此值:
webBuilder.UseSetting(WebHostDefaults.PreventHostingStartupKey, "true");
StartupAssembly
用来查找Startup
类的程序集。
键:startupAssembly
类型:字符串
默认值:app的程序集
环境变量:<PREFIX_>STARTUPASSEMBLY
使用配置或者调用UseStartup
来设置此值。UseStartup
方法可以使用程序集名称或者一个类型。如果多个UseStartup
被调用,最后一个优先考虑。
webBuilder.UseStartup("StartupAssemblyName");
webBuilder.UseStartup<Startup>();
URLs
以分号隔开的IP地址的列表,或者带有端口和协议的主机地址,服务应该监听它们的请求。举个例子,http://localhost:123
。使用“*”来指示服务应该监听来自任何IP地址或者任何带有特定端口和协议的主机名的请求(比如:http://*:5000
)。每一个URL都必须包含协议((http://
或者https://
)。支持的格式根据服务的不同会有变化。
键:urls
类型:字符串
默认值:http://localhost:5000
和 https://localhost:5001
环境变量:<PREFIX_>URLS
使用配置或者调用UseUrls
来设置此值:
webBuilder.UseUrls("http://*:5000;http://localhost:5001;https://hostname:5002");
Kestrel具有自己的终结点配置API。更多信息,请参考Kestrel web server implementation in ASP.NET Core。
WebRoot
应用 程序静态资产的相对路径。
键:webroot
类型:字符串
默认值:wwwroot
。{content root}/wwwroot 路径必须存在,如果这个路径不存在,便会使用无操作文件提供程序。
环境变量:<PREFIX_>WEBROOT
使用配置或者调用UseWebRoot
来设置此值:
webBuilder.UseWebRoot("public");
更多信息,请参考:
管理主机生命周期
调用内置的IHost实现的方法来启动和停止app。这些方法影响着所有在容器中注册的IHostedService 的实现。
Run
Run使得app开始运行,并阻塞调用线程直至主机关闭。
RunAsync
RunAsync 启动app并返回一个Task,当取消标记或触发关闭时其会完成。
RunConsoleAsync
RunConsoleAsync 启用控制台支持。创建并开启主机。并等待 Ctrl+C/SIGINT 或 SIGTERM 来关闭。
Start
Start 同步开启一个主机。
StartAsync
StartAsync 开始一个主机并返回一个Task,当取消标记或触发关闭时其会完成。
在StartAsync
开始时会调用WaitForStartAsync,在继续之前会等待直至StartAsync
的完成。这可以用来推迟启动直至收到外部事件的信号。
StopAsync
StopAsync 试图在给定的超时时间里停止主机。
WaitForShundown
WaitForShutdown 阻塞调用线程直至IHostLifetime触发了关闭事件,比如通过Ctrl+C/SIGINT 或SIGTERM。
WaitForShutdownAsync
WaitForShutdownAsync 返回一个可等待的任务,它会在通过给定的标识和调用StopAsync来触发关闭时候完成。
External control
使用可以从外部调用的方法来达到对主机生命周期直接控制的目的。
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)); } } }
额外资源