asp.net core 3.x 通用主机是如何承载asp.net core的-上
一、前言
上一篇《asp.net core 3.x 通用主机原理及使用》扯了下3.x中的通用主机,刚好有哥们写了篇《.NET Core 3.1和WorkerServices构建Windows服务》可以当做通用主机的案例来看。本篇主要聊下asp.net core 3.x中是如何使用通用主机来承载asp.net core本身的。
注:我是.net framework 4.x跳到.net core 3.x的,基本看源码总结的,可能某些地方理解不到位,所以此文只作为参考别全信哈。
阅读前提(参考老A的博客):
- 了解配置系统和选项模式
- 了解通用主机,可以看看上一篇文章
- 如果能大概理解Builder模式和上下文模式就更好了
目录:
- 通用主机回顾
- 通用主机是如何承载asp.net core的
- 核心类及使用要点
- 总结
二、回顾通用主机
2.1、IHost表示通用主机
微软为我们提供了一个默认实现(Microsoft.Extensions.Hosting.Internal.Host),它内部主要包含:ioc容器(服务提供器)、生命周期事件处理器、日志记录器、和IHostedService集合以及启动和停止方法。
2.1.1、ioc服务提供器:
用来存储各种服务对象,这个根容器是所有IHostedService共享的,各个IHostedService也可以创建主机的“范围IOC容器”。ioc容器包含微软为我们塞进去的,和我们自己塞进去的各种服务组件。在主机配置阶段微软会塞入:
- HostingEnvironment 主机环境,
- EnvironmentName主机环境(是开发模式?还是生产模式?)
- ApplicationName应用名称
- ContentRootPath主机的内容根路径
- ContentRootFileProvider内容提供器
- HostBuilderContext 主机创建过程中的上下文对象,在配置主机的多个步骤中传递数据。主要包含:HostingEnvironment和AppConfiguration应用配置对象
- AppConfiguration 应用配置对象,里面也包含主机配置对象
- IHostLifetime主机生命周期事件处理器
- IHostApplicationLifetime 应用生命周期事件处理器
- Internal.Host 作为默认主机
所以将来我们定义的类随时可以注入这些对象,这些对象是在HostBuilder中赋值的,请往下看
2.1.2、生命周期事件处理器
将来主机启动/停止时会触发回调相应的几个方法,比如:主机启动了 应用启动了 应用停止了,主机停止了。我们可以自定义一个事件处理器加入到ioc容器中来实现生命周期事件的订阅。
2.1.3、IHostedService集合
一个IHostedService的实现类就是一个应用。asp.net core本身就是一个应用。
2.1.4、启动流程
触发相应的生命周期事件、遍历启动所有IHostedService
2.2、HostBuilder表示主机构造器
它负责主机的配置和生成。它定义了几个委托集合,并提供相应的方法允许我们的代码向集合中加入自己的委托,这些委托主要是用来:
- 向ioc容器注册服务;
- 设置主机和应用配置对象的数据源;
- 配置容器本身(比如替换成别的依赖注入框架);
将来在调用Build生成最终的主机时会:
- 创建主机配置生成器ConfigurationBuilder,然后回调我们的代码提供的委托对配置对象的数据源进行设置,最终通过配置对象生成器.Build生成配置对象
- 创建HostingEnvironment(含义上面有说),默认用配置对象进行赋值,然后回调我们的代码提供的委托进一步设置主机环境对象
- 初始化BuilderContext(含义上面有说)
- 初始化应用配置生成器,套路给主机配置一样
- 初始化IOC容器,
- 先把上面说的对象丢入容器中,
- 注册默认主机, Internal.Host
- 注册选项模式需要的几个服务,
- 注册日志系统需要的服务
- 然后回调我们的委托,我们的委托可以注入各种主机需要的服务
- 配置ioc容器本身,我们对微软提供的ioc进行配置,或干脆替换为第三方依赖注入框架
- 嘴周从容器中解析得到主机
2.3、Host.CreateDefaultBuilder进一步简化主机的配置和创建
- 创建HostBuilder
- 设置内容根为当前应用程序根目录
- 将以"DOTNET_"的环境变量和命令行参数(如果有)作为“主机配置”的数据源
- 以以下数据作为“应用配置”的数据源
- json文件appsettings.json和appsettings.{env.EnvironmentName}.json
- 如果是开发模式,则添加一个特殊的json文件作为数据源,这个文件存储如:账号 密码 数据库连接字符串等比较机密的信息(文件查找路径有点复杂,后期补充)
- 添加环境变量作为配置源(没细看,也许是整个系统的环境变量)
- 尝试添加命令行参数配置源
- 添加日志记录系统需要的服务以及相关的配置
- 使用默认的ServiceProvider,当是开发模式时:在创建对象阶段开启依赖注入范围验证
以上为通用主机的大致内容,先有个印象,将来需要扩展时在研究源码
三、通用主机是如何承载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源码)
先来看个图:
核心任务是:
- 创建GenericWebHostBuilder,它是对通用主机构建器HostBuilder的一个包装,提供跟web相关的配置源的设置和服务的注册。构造函数中会做些初始化,默认配置
- 通过静态方法Host.ConfigureWebDefaults对GenericWebHostBuilder做进一步的默认配置
- 调用用户代码(我们自己写的)对GenericWebHostBuilder做进一步配置
所以文章后面部分我们将这个用来承载asp.net core的通用主机称为“Web主机”,把通用主机配置器HostBuilder的包装类GenericWebHostBuilder称为“Web主机配置器”
四、GenericWebHostBuilder
它包装了HostBuilder,所以可以把它理解为一个特殊的HostBuilder,特殊在它提供web相关的配置api,本质上还是向通用主机配置对象HostBuilder添加各种服务和配置源
4.1、GetSetting、UseSetting
GenericWebHostBuilder有个IConfiguration类型的属性,可以把它理解为跟web相关的配置对象,它会作为通用主机的配置源,由于通用主机的配置源又是应用配置的数据源,因此最后:应用配置对象 = 通用主机配置对象 + (web主机配置对象)GenericWebHostBuilder._config + 应用配置对象;
_config在构造函数中被初始化,唯一数据源是以"ASPNETCORE_"为前缀的环境变量
另外配置对象还在ExecuteHostingStartups被使用到,后面会详细讲
GetSetting、UseSetting这俩方法分别从_config读取和写入配置,所以我们可以在配置主机时更方便的向配置中加入一些值,也可以替换一些值来影响一些组件的配置
所以我们可以在配置web主机时通过UseSetting来快速设置/替换某些配置值,也可以在任意能获得GenericWebHostBuilder的地方调用GetSetting方便的获取配置值
4.2、IWebHostEnvironment、WebHostOptions、WebHostBuilderContext
在web主机配置过程中的多个步骤中经常会使用到这几个对象,我们对web主机进行配置时,提供的委托的参数也经常会携带者节参数,因此看看这几个东西是啥。
IWebHostEnvironment
web主机环境相关,它还继承IHostEnvironment,所以它包含以下内容:
- EnvironmentName 主机运行环境,是开发?生产?
- ApplicationName 应用名
- ContentRootPath 内容根,默认是应用程序所在目录
- ContentRootFileProvider 内容根对应的文件提供器
- WebRootPath web根,默认wwwroot,
- WebRootFileProvider web根对应的文件提供器
WebHostOptions
web主机选项对象,虽然是这个名字,但是并没有应用选项模式,且它是internal修饰的,因此我们写代码通常不会访问到它,但是它在GenericWebHostBuilder有些作用的
它内部包含根web相关的配置:
- ApplicationName:应用程序名
- PreventHostingStartup、HostingStartupAssemblies、HostingStartupExcludeAssemblies:插件/模块相关属性,参考《asp.net core 3.x 模块化开发之HostingStartup》
- Environment:应用程序当前运行,是开发模式?是生产环境?
- StartupAssembly:启动类Startup所在程序集
- WebRoot:web静态资源目录,通常对应那个wwwroot目录
- ContentRootPath:内容根路径,通常对应应用程序所在目录,
WebHostBuilderContext
= IWebHostEnvironment + IConfiguration
private WebHostBuilderContext GetWebHostBuilderContext(HostBuilderContext context)
GenericWebHostBuilder通过这个方法来创建WebHostBuilderContext,web主机配置器内部多个方法都会调用此方法。此方法执行过程大致步骤如下:
- 使用主机配置器上下文的配置对象来创建一个WebHostOptions,所以WebHostOptions上面那些属性都是通过配置来赋值的,由于HostBuilderContext的配置对象现在=主机配置对象 + 应用配置对象 + web主机配置对象,可想而知,我们可以通过多种途径来配置WebHostOptions的属性
- 创建WebHostBuilderContext
- Configuration = context.Configuration,
- HostingEnvironment = new HostingEnvironment()
- 通过HostingEnvironmentExtensions.Initialize对WebHostBuilderContext.HostingEnvironment进行初始化,其实就是将WebHostOptions中相应的属性赋值上去
- 最后HostBuilderContext和WebHostOptions被存储到HostBuilderContext.Properties缓存起来
所以我们平时可以通过多种途径来配置内容根、web根、应用名、运行环境(开发?生成?)
也可以在配置web主机时的委托中来通过WebHostBuilderContext来访问到这些属性和对应的文件提供器
由于IHostingEnvironment会以单例注册到容器,因此我们将来可以直接注入HostingEnvironment或者web主机环境对象
4.3、public IWebHostBuilder Configure(Action<WebHostBuilderContext, IApplicationBuilder> configure)
调用此方法传入一个委托,这个委托主要用来配置中间件管道,将来通用主机在启动时会启动代表asp.net core的GenericWebHostService,这时我们这个委托就会被调用。所以配置管道的代码是在HostBuilder.Build().Run()这个Run阶段执行,并不是在Build这步
这个方法跟UseStartup(下面会说)是冲突的,意思只能用其中一个,
要了解这个方法的原理,得先说说GenericWebHostServiceOptions,它是一个选项对象,看定义:
namespace Microsoft.AspNetCore.Hosting{
internal class GenericWebHostServiceOptions{
public Action<IApplicationBuilder> ConfigureApplication { get; set; }
public WebHostOptions WebHostOptions { get; set; }
public AggregateException HostingStartupExceptions { get; set; }
}
}
此对象应用了选项模式,(第5行)ConfigureApplication其实就代表了那个用来配置中间件管道的委托
public IWebHostBuilder Configure(Action<WebHostBuilderContext, IApplicationBuilder> configure){
_builder.ConfigureServices((context, services) => {
services.Configure<GenericWebHostServiceOptions>(options => {
var webhostBuilderContext = GetWebHostBuilderContext(context);
options.ConfigureApplication = app => configure(webhostBuilderContext, app);
});
}); return this;
}
所以无论是Startup中的Configre方法,还是这里传入的委托,最终都会以一个委托的形式赋值到GenericWebHostServiceOptions.ConfigureApplication属性上,而这个委托将来在主机启动阶段被调用,最终实现允许用户配置中间件管道的目的
为什么要提供两种配置中间件管道的方式呢?因为直接在Program.main里配置更简单,但是封装性不好,通过单独的Startup类更清晰。
所以我们配置中间件管道时除了可以在Startup.Configre中配置,也可以直接在Program.main里配置主机时通过GenericWebHostBuilder.Configure进行配置
未完待续....
asp.net core 3.x 通用主机是如何承载asp.net core的-上的更多相关文章
- asp.net core 3.x 通用主机原理及使用
一.前言 只是讲asp.net core 3.x通用主机的大致原理,这些东西是通过查看源码以及自己根据经验总结得来的,在文章中不会深入源码,因为个人觉得懂原理就晓得扩展点,后期碰到有需求的时候再仔细去 ...
- asp.net core 系列 17 通用主机 IHostBuilder
一.概述 ASP.NET Core 通用主机 (HostBuilder),该主机对于托管不处理 HTTP 请求的应用非常有用.通用主机的目标是将 HTTP 管道从 Web 主机 API 中分离出来,从 ...
- 翻译 - ASP.NET Core 基本知识 - 通用主机 (Generic Host)
翻译自 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-5.0 ...
- .NET Core 中的通用主机和后台服务
简介 我们在做项目的时候, 往往要处理一些后台的任务. 一般是两种, 一种是不停的运行,比如消息队列的消费者.另一种是定时任务. 在.NET Framework + Windows环境里, 我们一般会 ...
- .Net Core中的通用主机(一)——系统配置
ASP.NET Core 2.0 中的 WebHost(实现 IWebHost 的基类)是用于为进程提供 HTTP 服务器功能的基础结构项目,例如,如果正在实现 MVC Web 应用或 Web API ...
- .Net Core中的通用主机(二)——托管服务
前文介绍了.Net core的通用主机的配置,在基础配置完成后,下一步就是注册我们的后台任务了..net core提供了一个通用的后台服务接口IHostedService,称为托管服务.一个注册托管服 ...
- Asp.net Core 2.1新功能Generic Host(通用主机),了解一下
什么是Generic Host ? 这是在Asp.Net Core 2.1加入了一种新的Host,现在2.1版本的Asp.Net Core中,有了两种可用的Host. Web Host –适用于托管W ...
- (16)ASP.NET Core 通用主机(HostBuilder)
1.前言 ASP.NET Core应用程序可以配置和启动主机(Host).主机负责应用程序启动和生命周期管理.通用主机用于无法处理HTTP请求的应用程序.通用主机的用途是将HTTP管道从Web主机AP ...
- asp.net core 系列 16 Web主机 IWebHostBuilder
一.概述 在asp.net core中,Host主机负责应用程序启动和生存期管理.host主机包括Web 主机(IWebHostBuilder)和通用主机(IHostBuilder).Web 主机是适 ...
随机推荐
- poj 1787 Charlie's Change (多重背包可作完全背包)
Charlie's Change Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 3792 Accepted: 1144 ...
- Flex AIR应用GPS定位功能(Android和IOS)
说明: 使用AIR进行GPS定位功能实现时,会经常判断GPS是否打开.一般的官方或者书上的介绍的方法,测试后,只能对Android系统进行判断,而对ios系统则无法进行判断. 经过研究测试,终于解决实 ...
- 浅谈集合框架三、Map常用方法及常用工具类
最近刚学完集合框架,想把自己的一些学习笔记与想法整理一下,所以本篇博客或许会有一些内容写的不严谨或者不正确,还请大神指出.初学者对于本篇博客只建议作为参考,欢迎留言共同学习. 之前有介绍集合框架的体系 ...
- H3C 通配符掩码的应用示例
- java 打印流
(只有两个,PrintWriter和PrintStream) 思考:如果现在要想完成一个字符串或者是boolean型或者是字符型的数据输出使用OutputStream是否方便? 肯定是不方便的,因为O ...
- java 类加载器的委托机制
l 当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢? 1.首先当前线程的类加载器去加载线程中的第一个类. 2.如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B. 3 ...
- Vue中的scoped及穿透方法(修改第三方组件局部的样式)
何为scoped? 在vue文件中的style标签上,有一个特殊的属性:scoped.当一个style标签拥有scoped属性时,它的CSS样式就只能作用于当前的组件,也就是说,该样式只能适用于当前组 ...
- H3C配置热键--hotkey---系统视图
Hotkey作用 hotkey 命令用来为某一快捷键指定相应的命令行. undo hotkey 命令用来恢复系统的默认值. —————————————————————————————————————— ...
- Linux 内核class_simple 接口
class_simple 接口意图是易于使用, 以至于没人会抱怨没有暴露至少一个包含设备的被 分配的号的属性. 使用这个接口只不过是一对函数调用, 没有通常的和 Linux 设备模型 关联的样板. 第 ...
- 【58.75%】【BZOJ 1087】[SCOI2005]互不侵犯King
Time Limit: 10 Sec Memory Limit: 162 MB Submit: 3040 Solved: 1786 [Submit][Status][Discuss] Descri ...