一、前言

上一篇《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. [C#] 调试silverlight的时候,总是报“向占位程序传送了空的索引指针”

    这是由于visual studio在调试silverlight的时候,必须和ie一起工作. 按照以下步骤可以把ie设为visual studio的默认浏览器(不用修改操作系统的默认浏览器): 1) 在 ...

  2. [C++] 检查随机内存溢出

    C++程序的随机内存溢出是非常难处理的,windows提供了一些工具来缓解这个问题. windows debuger提供的Global Flags可以设置"enable heap tail ...

  3. ubuntu中桌面图标的配置

    在网上随处可以找到怎么样把应用程序的图标放到桌面上,我刚用ubuntu时也是按照网上的做法,一步一步的做的,现将网上的做法复制下来: 桌面配置文件简述\label{sec:desktop file} ...

  4. 21个项目玩转深度学习:基于TensorFlow的实践详解06—人脸检测和识别——项目集锦

    摘自:https://github.com/azuredsky/mtcnn-2 mtcnn - Multi-task CNN library language dependencies comment ...

  5. H3C VLAN配置示例

  6. C# 简单读取文件

    本文告诉大家如何使用最少的代码把一个文件读取二进制,读取为字符串 现在写了一些代码,想使用最少代码来写简单的读文件,所以我就写了这个文章 读取文件为二进制 private byte[] ReadFil ...

  7. Vue中通过属性绑定为元素绑定style行内样式

    1.直接在元素上通过:style的形式,书写样式对象 2.将样式对象定义在data中,并直接引用到:style中 3.在:style中通过数组,引用多个data上的样式对象

  8. Struts 2三种方式实现Ajax

    Ajax本质上和普通的HTTP请求是一样的,只不过普通的HTTP请求是给人看的,而Ajax请求是给JS代码去用的. 所以Ajax请求的页面一般比普通的HTTP请求的响应内容还要简单,可能是一个页面的一 ...

  9. 【Docker】Ubuntu16.04将Docker升级至最新版

    1.使用curl升级到最新版 curl -fsSL https://get.docker.com/ | sh 2.重启Docker sudo systemctl restart docker 3.设置 ...

  10. HDU1172猜数字 [模拟]

    1.题意 任务是猜一个四位数,每次尝试后会给出这次猜中了几个数字和猜中了几个位置,求能否根据尝试的记录给出答案 2.分析 数据给出查询次数和每次查询的数及其有几个数和几个位置符合,值得注意的是,猜对的 ...