上一篇《asp.net core 3.x 通用主机原理及使用》扯了下3.x中的通用主机,恰好有哥们写了篇《.NET Core 3.1和WorkerServices构建Windows服务》能够当作通用主机的案例来看。本篇主要聊下asp.net core 3.x中是如何使用通用主机来承载asp.net core自己的。html
注:我是.net framework 4.x跳到.net core 3.x的,基本看源码总结的,可能某些地方理解不到位,因此此文只做为参考别全信哈。web
阅读前提(参考老A的博客):数据库
目录:json
微软为咱们提供了一个默认实现(Microsoft.Extensions.Hosting.Internal.Host),它内部主要包含:ioc容器(服务提供器)、生命周期事件处理器、日志记录器、和IHostedService集合以及启动和中止方法。api
用来存储各类服务对象,这个根容器是全部IHostedService共享的,各个IHostedService也能够建立主机的“范围IOC容器”。ioc容器包含微软为咱们塞进去的,和咱们本身塞进去的各类服务组件。在主机配置阶段微软会塞入:缓存
因此未来咱们定义的类随时能够注入这些对象,这些对象是在HostBuilder中赋值的,请往下看app
未来主机启动/中止时会触发回调相应的几个方法,好比:主机启动了 应用启动了 应用中止了,主机中止了。咱们能够自定义一个事件处理器加入到ioc容器中来实现生命周期事件的订阅。框架
一个IHostedService的实现类就是一个应用。asp.net core自己就是一个应用。asp.net
触发相应的生命周期事件、遍历启动全部IHostedServiceide
它负责主机的配置和生成。它定义了几个委托集合,并提供相应的方法容许咱们的代码向集合中加入本身的委托,这些委托主要是用来:
未来在调用Build生成最终的主机时会:
以上为通用主机的大体内容,先有个印象,未来须要扩展时在研究源码
3、通用主机是如何承载asp.net core的
asp.net core 3.x开始直接使用通用主机,主要思路是对通用主机作跟web相关配置(添加跟web相关的配置源和注册服务),关键是会将GenericWebHostService注册到ioc容器中。对于通用主机来讲所谓的应用就是一个实现了IHostedService的类。GenericWebHostService就是这样一个类,它就基本表明了asp.net core。对于通用主机来讲asp.net core不过是一个应用而已。未来通用主机启动时天然是启动GenericWebHostService
注:GenericWebHostService会在启动时建立ApplicationBuilder,而后对其进行配置(中间件管道),而后生成一个Application,最后拿到配置好的IServer(如KestrlServer)而后传入Application并启动它,Server开始监听http请求,后续请求抵达时由Application对象负责将请求传入中间件管道*(大体这么个流程,还没详细去看GenericWebHostService源码)
先来看个图:
核心任务是:
因此文章后面部分咱们将这个用来承载asp.net core的通用主机称为“Web主机”,把通用主机配置器HostBuilder的包装类GenericWebHostBuilder称为“Web主机配置器”
它包装了HostBuilder,因此能够把它理解为一个特殊的HostBuilder,特殊在它提供web相关的配置api,本质上仍是向通用主机配置对象HostBuilder添加各类服务和配置源
GenericWebHostBuilder有个IConfiguration类型的属性,能够把它理解为跟web相关的配置对象,它会做为通用主机的配置源,因为通用主机的配置源又是应用配置的数据源,所以最后:应用配置对象 = 通用主机配置对象 + (web主机配置对象)GenericWebHostBuilder._config + 应用配置对象;
_config在构造函数中被初始化,惟一数据源是以"ASPNETCORE_"为前缀的环境变量
另外配置对象还在ExecuteHostingStartups被使用到,后面会详细讲
GetSetting、UseSetting这俩方法分别从_config读取和写入配置,因此咱们能够在配置主机时更方便的向配置中加入一些值,也能够替换一些值来影响一些组件的配置
因此咱们能够在配置web主机时经过UseSetting来快速设置/替换某些配置值,也能够在任意能得到GenericWebHostBuilder的地方调用GetSetting方便的获取配置值
在web主机配置过程当中的多个步骤中常常会使用到这几个对象,咱们对web主机进行配置时,提供的委托的参数也常常会携带者节参数,所以看看这几个东西是啥。
IWebHostEnvironment
web主机环境相关,它还继承IHostEnvironment,因此它包含如下内容:
WebHostOptions
web主机选项对象,虽然是这个名字,可是并无应用选项模式,且它是internal修饰的,所以咱们写代码一般不会访问到它,可是它在GenericWebHostBuilder有些做用的
它内部包含根web相关的配置:
WebHostBuilderContext
= IWebHostEnvironment + IConfiguration
private WebHostBuilderContext GetWebHostBuilderContext(HostBuilderContext context)
GenericWebHostBuilder经过这个方法来建立WebHostBuilderContext,web主机配置器内部多个方法都会调用此方法。此方法执行过程大体步骤以下:
因此咱们平时能够经过多种途径来配置内容根、web根、应用名、运行环境(开发?生成?)
也能够在配置web主机时的委托中来经过WebHostBuilderContext来访问到这些属性和对应的文件提供器
因为IHostingEnvironment会以单例注册到容器,所以咱们未来能够直接注入HostingEnvironment或者web主机环境对象
调用此方法传入一个委托,这个委托主要用来配置中间件管道,未来通用主机在启动时会启动表明asp.net core的GenericWebHostService,这时咱们这个委托就会被调用。因此配置管道的代码是在HostBuilder.Build().Run()这个Run阶段执行,并非在Build这步
这个方法跟UseStartup(下面会说)是冲突的,意思只能用其中一个,
要了解这个方法的原理,得先说说GenericWebHostServiceOptions,它是一个选项对象,看定义:
1 namespace Microsoft.AspNetCore.Hosting{ 3 internal class GenericWebHostServiceOptions{ 5 public Action<IApplicationBuilder> ConfigureApplication { get; set; } 6 public WebHostOptions WebHostOptions { get; set; } 8 public AggregateException HostingStartupExceptions { get; set; } 10 } 11 }
此对象应用了选项模式,(第5行)ConfigureApplication其实就表明了那个用来配置中间件管道的委托
1 public IWebHostBuilder Configure(Action<WebHostBuilderContext, IApplicationBuilder> configure){ 2 _builder.ConfigureServices((context, services) => { 3 services.Configure<GenericWebHostServiceOptions>(options => { 4 var webhostBuilderContext = GetWebHostBuilderContext(context); 5 options.ConfigureApplication = app => configure(webhostBuilderContext, app); 6 }); 7 }); 8 9 return this; 10 }
因此不管是Startup中的Configre方法,仍是这里传入的委托,最终都会以一个委托的形式赋值到GenericWebHostServiceOptions.ConfigureApplication属性上,而这个委托未来在主机启动阶段被调用,最终实现容许用户配置中间件管道的目的
为何要提供两种配置中间件管道的方式呢?由于直接在Program.main里配置更简单,可是封装性很差,经过单独的Startup类更清晰。
因此咱们配置中间件管道时除了能够在Startup.Configre中配置,也能够直接在Program.main里配置主机时经过GenericWebHostBuilder.Configure进行配置
未完待续....