一、前言

上一篇《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源码)

先来看个图:

核心任务是:

  1. 创建GenericWebHostBuilder,它是对通用主机构建器HostBuilder的一个包装,提供跟web相关的配置源的设置和服务的注册。构造函数中会做些初始化,默认配置
  2. 通过静态方法Host.ConfigureWebDefaults对GenericWebHostBuilder做进一步的默认配置
  3. 调用用户代码(我们自己写的)对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的-上的更多相关文章

  1. asp.net core 3.x 通用主机原理及使用

    一.前言 只是讲asp.net core 3.x通用主机的大致原理,这些东西是通过查看源码以及自己根据经验总结得来的,在文章中不会深入源码,因为个人觉得懂原理就晓得扩展点,后期碰到有需求的时候再仔细去 ...

  2. asp.net core 系列 17 通用主机 IHostBuilder

    一.概述 ASP.NET Core 通用主机 (HostBuilder),该主机对于托管不处理 HTTP 请求的应用非常有用.通用主机的目标是将 HTTP 管道从 Web 主机 API 中分离出来,从 ...

  3. 翻译 - ASP.NET Core 基本知识 - 通用主机 (Generic Host)

    翻译自 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-5.0 ...

  4. .NET Core 中的通用主机和后台服务

    简介 我们在做项目的时候, 往往要处理一些后台的任务. 一般是两种, 一种是不停的运行,比如消息队列的消费者.另一种是定时任务. 在.NET Framework + Windows环境里, 我们一般会 ...

  5. .Net Core中的通用主机(一)——系统配置

    ASP.NET Core 2.0 中的 WebHost(实现 IWebHost 的基类)是用于为进程提供 HTTP 服务器功能的基础结构项目,例如,如果正在实现 MVC Web 应用或 Web API ...

  6. .Net Core中的通用主机(二)——托管服务

    前文介绍了.Net core的通用主机的配置,在基础配置完成后,下一步就是注册我们的后台任务了..net core提供了一个通用的后台服务接口IHostedService,称为托管服务.一个注册托管服 ...

  7. Asp.net Core 2.1新功能Generic Host(通用主机),了解一下

    什么是Generic Host ? 这是在Asp.Net Core 2.1加入了一种新的Host,现在2.1版本的Asp.Net Core中,有了两种可用的Host. Web Host –适用于托管W ...

  8. (16)ASP.NET Core 通用主机(HostBuilder)

    1.前言 ASP.NET Core应用程序可以配置和启动主机(Host).主机负责应用程序启动和生命周期管理.通用主机用于无法处理HTTP请求的应用程序.通用主机的用途是将HTTP管道从Web主机AP ...

  9. asp.net core 系列 16 Web主机 IWebHostBuilder

    一.概述 在asp.net core中,Host主机负责应用程序启动和生存期管理.host主机包括Web 主机(IWebHostBuilder)和通用主机(IHostBuilder).Web 主机是适 ...

随机推荐

  1. poj 1787 Charlie's Change (多重背包可作完全背包)

    Charlie's Change Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 3792   Accepted: 1144 ...

  2. Flex AIR应用GPS定位功能(Android和IOS)

    说明: 使用AIR进行GPS定位功能实现时,会经常判断GPS是否打开.一般的官方或者书上的介绍的方法,测试后,只能对Android系统进行判断,而对ios系统则无法进行判断. 经过研究测试,终于解决实 ...

  3. 浅谈集合框架三、Map常用方法及常用工具类

    最近刚学完集合框架,想把自己的一些学习笔记与想法整理一下,所以本篇博客或许会有一些内容写的不严谨或者不正确,还请大神指出.初学者对于本篇博客只建议作为参考,欢迎留言共同学习. 之前有介绍集合框架的体系 ...

  4. H3C 通配符掩码的应用示例

  5. java 打印流

    (只有两个,PrintWriter和PrintStream) 思考:如果现在要想完成一个字符串或者是boolean型或者是字符型的数据输出使用OutputStream是否方便? 肯定是不方便的,因为O ...

  6. java 类加载器的委托机制

    l 当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢? 1.首先当前线程的类加载器去加载线程中的第一个类. 2.如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B. 3 ...

  7. Vue中的scoped及穿透方法(修改第三方组件局部的样式)

    何为scoped? 在vue文件中的style标签上,有一个特殊的属性:scoped.当一个style标签拥有scoped属性时,它的CSS样式就只能作用于当前的组件,也就是说,该样式只能适用于当前组 ...

  8. H3C配置热键--hotkey---系统视图

    Hotkey作用 hotkey 命令用来为某一快捷键指定相应的命令行. undo hotkey 命令用来恢复系统的默认值. —————————————————————————————————————— ...

  9. Linux 内核class_simple 接口

    class_simple 接口意图是易于使用, 以至于没人会抱怨没有暴露至少一个包含设备的被 分配的号的属性. 使用这个接口只不过是一对函数调用, 没有通常的和 Linux 设备模型 关联的样板. 第 ...

  10. 【58.75%】【BZOJ 1087】[SCOI2005]互不侵犯King

    Time Limit: 10 Sec  Memory Limit: 162 MB Submit: 3040  Solved: 1786 [Submit][Status][Discuss] Descri ...