asp.net core 3.x 通用主机原理及使用
一、前言
只是讲asp.net core 3.x通用主机的大致原理,这些东西是通过查看源码以及自己根据经验总结得来的,在文章中不会深入源码,因为个人觉得懂原理就晓得扩展点,后期碰到有需求的时候再仔细去研究源码也不迟。
阅读前你应该先去了解下(推荐博客园老A的博客):
- asp.net core中的依赖注入、
- 配置,
讲解的方式是:
- 概述
- 逐一介绍核心类及扩展方式
- 通常我们如何使用
- 总结
二、概述
以前的控制台应用程序、winform程序启动时main首先被执行,后续都是我们自己的代码来实现框架和业务上的东东,比如我们要使用配置就ConfigurationManager.AppSettings... 若想使用依赖注入则需要引入第三方框架,比如autofact。asp.net framework时代也类似
在.net core 3.0之前的版本默认使用的是IWebHost,它内部定义了IOC容器(服务注册体现在Startup.ConfigServices),和各种配置源的设置(体现在Program配置主机时),我们后续的Controler、View、包括业务代码可以很容易做依赖注入和获取配置信息(包括运用选项模式)
有时候我们希望写一个服务,但是这个服务并不是用来做api/web,处理http请求的,比如想做一个物联网的后端采集服务,一直等待远端硬件设备提交实时数据过来,后端进行处理。但是又希望使用asp.net core提供的 配置、依赖注入、日志 和其它功能。后来微软就将asp.net core中的这套东西抽离出来了,叫做通用主机,用来承载任何服务,这些自定义服务中就可以很方便地使用配置、依赖注入、日志、和其它功能。现在asp.net core只是由通用主机承载的其中一种服务。
2.1、默认情况下主要的实现思路是:
2.1.1、定义(微软定义好的):
- 定义HOST,它包含IOC根容器、主机和应用程序的生命周期事件定定义、IHostedService集合(一个实例就是一个服务或者叫应用,asp.net core就是一个这样的实例)
- 允许调用方提供一堆委托来向IOC中注册服务、和设置主机和应用的“配置源”
- 提供向主机添加IHostedService的实现对象的方法
- 允许调用方注册主机和应用在启动和停止阶段触发的相应事件
2.1.2、配置(我们的代码,微软定义很多辅助方法):
- 创建IHost实例
- 向Host的IOC容器中注册各种服务
- 配置主机和应用程序的“配置源
- 向主机内部添加IHostedService实例(也就是我们最终的服务)
- 主机和应用的生命周期事件,来实现一些特殊任务
2.1.3、启动阶段(微软定义好的)
- 上面所谓的配置基本都是通过委托实现的(通常微软提供的各种扩展方法最终也是执行委托),回调这些委托以设置“配置源”和注册服务
- 最后遍历启动HostedService
- 在启动过程中还会回调相应的生命周期事件
2.2、啥是应用?
上面提了几次“应用”,现在对于主机来说asp.net core框架就是一个应用、我们上面举例说的"物联网后端服务"是另一个应用。从代码上来说就是一个IHostedService的实现。
主机和应用是一对多的关系,多个应用可以共享主机的信息,如:主机的IOC容器、主机的配置。应用配置。应用当然也可以自己去创建自己的IOC根容器和配置对象
主机配置和应用配置有关系?这两个配置对象都存在于Host中,主机配置是只跟主机相关的配置,应用配置是主机中多个应用共享的配置,如果主机中只有一个应用,那么完全可以拿它做最终的应用配置。另外应用配置包含主机配置
注意:在理解时要记住我们现在的目的是讲解通用主机,意思是可以承载你自己定义的服务的主机,别去想什么mvc controller action 路由之类的
三、核心类
下面分别介绍下主机中的几个核心默认实现类,几乎每个类都有对应的接口,为了缩短篇幅、便于理解就不讲接口了。
3.1、Host
它代表主机,用来宿主(承载)我们应用(一个IHostedService的实现)。
主要包含:日志、主机和应用的生命周期事件、IOC根容器、主机的选项对象、启动停止/停止方法。
接口中只定义了:IOC根容器 + Start + Stop方法
它在Program.Main中被创建、配置和启动
默认实现Microsoft.Extensions.Hosting.Internal.Host,它是一个internal的类,这个主机将来被启动时:
- 触发主机的WaitForStartAsync事件
- 逐一启动主机累不的hostedService
- 触发_applicationLifetime?.NotifyStarted();事件
- 停止时就反过来,先逐一停止hostedService,触发响应事件、最后停止主机
扩展:
因为默认Host是internal修饰的,所以无法继承
- 自定义实现IHost;(这不说了,你可以随心所欲)
- 订阅主机和应用的生命周期事件(实现IHostLifetime、IHostApplicationLifetime并添加到IOC容器)
大部分情况下方式2实现起来更容易也更常见
提一嘴,asp.net core 3.x现在也是使用的这个默认主机,只是在上面做了根web相关的配置,将在下一篇讲解
3.2、HostBuilder
Host的职责只是完成主机该有的功能,那么它的创建及配置最好另外定义一个类HostBuilder,它是Host的创建器(工厂),我们通常
- 在系统启动时(Program.Man)先创建HostBuilder,
- 然后进行配置(向IOC容器注册服务,设置主机和应用的"配置源"),
- 最后调用Build方法生成我们最终的Host
通过接口IHostBuilder源码可以初略看出它(通过委托的方式)提供以下功能
- 设置主机和应用的“配置源”
- 配置IOC容器本身
- 想IOC容器添加服务
- 根据以后配置创建Host
- 有个Properties属性,是个字典类型,可以在构建Host的多个步骤中传递数据
扩展:
对于我们使用者来说主要是通过它的方法向内部塞入各种委托,以达到向IOC容器注册服务和设置主机和应用的“配置源”
也可以但估计很少去实现主机的IHostBuilder;继承HostBuilder意义也不大,因为它没有提供抽象和虚方法
默认Build流程
初始化主机配置对象IConfiguration,主要是回调,主机没有做其它的
初始化主机环境对象_hostingEnvironment
- 应用程序名字从上一步的主机配置里来
- 环境名(开发?调试?)从配置里来,若没有则默认是生产模式"Production"
- 内容根也从配置里来,若没有则是当前程序路径
- 根据内容跟创建一个ContentRootFileProvider 实现类是PhysicalFileProvider
初始化HostBuilderContext,根据上面的配置和环境创建这个上下文(这里只是暂时用的主机配置,下面会被替换成应用的配置)
初始化应用配置
- 以上面的内容根作为配置查找的根(若将来提供物理文件作为配置源时需要此属性)
- 将主机配置塞入这个应用配置,所以应用配置=主机配置+回调后的配置
- 最后将HostBuilderContext的Configuration替换为此配置对象
创建IOC容器
- 创建ServiceCollection,并将上面的几个对象以单利模式放入进去
- 还要放入IHostApplicationLifetime和IHostLifetime和Host
- 开启选项模式,注册日志
- 回调configureServicesAction
- 调用工厂_serviceProviderFactory创建ServiceProvider
- 回调_configureContainerActions
- 最后返回容器
调用容器解析并返回Host
3.3、HostBuilder的工厂方法Host.CreateDefaultBuilder
上面有了Host,也有了对应的创建器HostBuilder,为啥还要再提供一个工厂方法呢?
因为职责分离原则,Host只负责承载应用并提供容器和设置配置源;HostBuilder只是负责配置并创建Host,尽可能提供一些默认值(前提时将来调用方未提供那些参数)。此时我们可以直接用HostBuilder来创建Host并启动它,但别忘了.net core是一个通用框架,它应提供一个更简洁的方式来创建最终的Host,因此它提供了静态方法Host.CreateDefaultBuilder,它尽可能提供更多的默认值,核心任务如下:
- new HostBuilder
- 设置程序的当前目录为内容根
- 为主机配置 设置 环境变量作为配置源(只关注前缀DOTNET_的环境变量)
- 为应用配置设置 以“appsettings.json”和“appsettings.{env.EnvironmentName}.json”作为配置源;同时也将环境变量加入到应用的配置源;最后将命令行参数加入到配置源
- 配置日志
- 若是开发模式,还会配置依赖注入的范围验证
四、从使用者的角度来说
通过自定义实现IHostedService的类来实现我们的服务,我们的服务中的类可以
- 直接使用依赖注入,
- 也可以通过依赖注入获取主机配置和全局应用配置对象,或者更方便的是进一步使用选项模式
- 我们也可以注入日志记录器
- 由于主机创建过程的相关数据几乎都放进了IOC容器中,因此我们也可以通过依赖注入拿到
- 其它...
在Program.man调用Host.CreateDefaultBuilder,如果需要,提供相应的委托来注册服务和设置主机和应用的“配置源”,最好是通过相关扩展方法和自定义扩展方法。重点是记得注入我们自己的服务实现类
五、总结
.net core为我们提供了新的承载应用(包括但不仅限于asp.net core)的方式-->通用主机,通过它我们可以很容易的在自己的应用中使用依赖注入、配置、日志等,你可以发挥想象实现很多牛B的框架。
asp.net core 3.x开始默认也是使用它来承载的
核心的Host、HostBuilder、Host.CreateDefaultBuilder实现了通用主机,并提供了扩展点
最后我想说如果在.net core上提供一个默认的aop方案就更完美了。
下一篇试试说下asp.net core是如何承载到通用主机上的
asp.net core 3.x 通用主机原理及使用的更多相关文章
- asp.net core 3.x 通用主机是如何承载asp.net core的-上
一.前言 上一篇<asp.net core 3.x 通用主机原理及使用>扯了下3.x中的通用主机,刚好有哥们写了篇<.NET Core 3.1和WorkerServices构建Win ...
- 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 ...
- asp.net core 系列 16 Web主机 IWebHostBuilder
一.概述 在asp.net core中,Host主机负责应用程序启动和生存期管理.host主机包括Web 主机(IWebHostBuilder)和通用主机(IHostBuilder).Web 主机是适 ...
- .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 基本知识 - Web 主机 (Web Host)
翻译自 https://docs.microsoft.com/en-us/aspnet/core/fundamentals/host/web-host?view=aspnetcore-5.0 ASP. ...
- Asp.Net Core EndPoint 终点路由工作原理解读
一.背景 在本打算写一篇关于Identityserver4 的文章时候,确发现自己对EndPoint -终结点路由还不是很了解,故暂时先放弃了IdentityServer4 的研究和编写:所以才产生了 ...
随机推荐
- @bzoj - 4922@ [Lydsy1706月赛]Karp-de-Chant Number
目录 @description@ @solution@ @accepted code@ @details@ @description@ 卡常数被称为计算机算法竞赛之中最神奇的一类数字,主要特点集中于令 ...
- Top 10 open source projects of 2015
Top 10 open source projects of 2015 Posted 15 Dec 2015Jen Wike Huger (Red Hat)Feed 188 up 31 comment ...
- cp拷贝
1 cp 拷贝.复制 NAME cp - copy files and directories SYNOPSIS cp [OPTION]... [-T] SOURCE DEST -- c ...
- javascript和jquery 移除事件 和 改变样式
javascript移除事件: document.getElementById("word").onmouseover = null; javascript改变样式: docume ...
- Python--day21--异常处理
初识try: except -->异常处理 万能异常的用法:except Exception as error:
- [转]在eclipse中,用maven创建一个web项目工程
1.在eclipse中用maven创建项目,右键new>>Maven Project 2.点击next继续 3.点击next继续,选择maven-archetype-webapp, 4.点 ...
- P1105 数列
题目描述 给定一个正整数 \(k(2 \le k \le 15)\) ,把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当 \(k = 3\) 时,这个序列是: 1,3,4, ...
- 《Spring 5官方文档》 Spring AOP的经典用法
原文链接 在本附录中,我们会讨论一些初级的Spring AOP接口,以及在Spring 1.2应用中所使用的AOP支持. 对于新的应用,我们推荐使用 Spring AOP 2.0来支持,在AOP章节有 ...
- 【js】vue 2.5.1 源码学习 (七) 初始化之 initState 响应式系统基本思路
大体思路(六) 本节内容: 一.生命周期的钩子函数的实现 ==> callHook(vm , 'beforeCreate') beforeCreate 实例创建之后 事件数据还未创建 二.初始化 ...
- 21个项目玩转深度学习:基于TensorFlow的实践详解02—CIFAR10图像识别
cifar10数据集 CIFAR-10 是由 Hinton 的学生 Alex Krizhevsky 和 Ilya Sutskever 整理的一个用于识别普适物体的小型数据集.一共包含 10 个类别的 ...