.NET Core 3.1通用主机原理及使用
一、前言
只是講asp.net core 3.x通用主機(jī)的大致原理,這些東西是通過查看源碼以及自己根據(jù)經(jīng)驗(yàn)總結(jié)得來的,在文章中不會深入源碼,因?yàn)閭€(gè)人覺得懂原理就曉得擴(kuò)展點(diǎn),后期碰到有需求的時(shí)候再仔細(xì)去研究源碼也不遲。
閱讀前你應(yīng)該先去了解下(推薦博客園老A的博客):
asp.net core中的依賴注入、
配置,
講解的方式是:
概述
逐一介紹核心類及擴(kuò)展方式
通常我們?nèi)绾问褂?/p>
總結(jié)
二、概述
以前的控制臺應(yīng)用程序、winform程序啟動(dòng)時(shí)main首先被執(zhí)行,后續(xù)都是我們自己的代碼來實(shí)現(xiàn)框架和業(yè)務(wù)上的東東,比如我們要使用配置就ConfigurationManager.AppSettings... 若想使用依賴注入則需要引入第三方框架,比如autofact。asp.net framework時(shí)代也類似
在.net core 3.0之前的版本默認(rèn)使用的是IWebHost,它內(nèi)部定義了IOC容器(服務(wù)注冊體現(xiàn)在Startup.ConfigServices),和各種配置源的設(shè)置(體現(xiàn)在Program配置主機(jī)時(shí)),我們后續(xù)的Controler、View、包括業(yè)務(wù)代碼可以很容易做依賴注入和獲取配置信息(包括運(yùn)用選項(xiàng)模式)
有時(shí)候我們希望寫一個(gè)服務(wù),但是這個(gè)服務(wù)并不是用來做api/web,處理http請求的,比如想做一個(gè)物聯(lián)網(wǎng)的后端采集服務(wù),一直等待遠(yuǎn)端硬件設(shè)備提交實(shí)時(shí)數(shù)據(jù)過來,后端進(jìn)行處理。但是又希望使用asp.net core提供的 配置、依賴注入、日志 和其它功能。后來微軟就將asp.net core中的這套東西抽離出來了,叫做通用主機(jī),用來承載任何服務(wù),這些自定義服務(wù)中就可以很方便地使用配置、依賴注入、日志、和其它功能。現(xiàn)在asp.net core只是由通用主機(jī)承載的其中一種服務(wù)。
2.1、默認(rèn)情況下主要的實(shí)現(xiàn)思路是:
2.1.1、定義(微軟定義好的):
定義HOST,它包含IOC根容器、主機(jī)和應(yīng)用程序的生命周期事件定定義、IHostedService集合(一個(gè)實(shí)例就是一個(gè)服務(wù)或者叫應(yīng)用,asp.net core就是一個(gè)這樣的實(shí)例)
允許調(diào)用方提供一堆委托來向IOC中注冊服務(wù)、和設(shè)置主機(jī)和應(yīng)用的“配置源”
提供向主機(jī)添加IHostedService的實(shí)現(xiàn)對象的方法
允許調(diào)用方注冊主機(jī)和應(yīng)用在啟動(dòng)和停止階段觸發(fā)的相應(yīng)事件
2.1.2、配置(我們的代碼,微軟定義很多輔助方法):
創(chuàng)建IHost實(shí)例
向Host的IOC容器中注冊各種服務(wù)
配置主機(jī)和應(yīng)用程序的“配置源
向主機(jī)內(nèi)部添加IHostedService實(shí)例(也就是我們最終的服務(wù))
主機(jī)和應(yīng)用的生命周期事件,來實(shí)現(xiàn)一些特殊任務(wù)
2.1.3、啟動(dòng)階段(微軟定義好的)
上面所謂的配置基本都是通過委托實(shí)現(xiàn)的(通常微軟提供的各種擴(kuò)展方法最終也是執(zhí)行委托),回調(diào)這些委托以設(shè)置“配置源”和注冊服務(wù)
最后遍歷啟動(dòng)HostedService
在啟動(dòng)過程中還會回調(diào)相應(yīng)的生命周期事件
2.2、啥是應(yīng)用?
上面提了幾次“應(yīng)用”,現(xiàn)在對于主機(jī)來說asp.net core框架就是一個(gè)應(yīng)用、我們上面舉例說的"物聯(lián)網(wǎng)后端服務(wù)"是另一個(gè)應(yīng)用。從代碼上來說就是一個(gè)IHostedService的實(shí)現(xiàn)。
主機(jī)和應(yīng)用是一對多的關(guān)系,多個(gè)應(yīng)用可以共享主機(jī)的信息,如:主機(jī)的IOC容器、主機(jī)的配置。應(yīng)用配置。應(yīng)用當(dāng)然也可以自己去創(chuàng)建自己的IOC根容器和配置對象
主機(jī)配置和應(yīng)用配置有關(guān)系?這兩個(gè)配置對象都存在于Host中,主機(jī)配置是只跟主機(jī)相關(guān)的配置,應(yīng)用配置是主機(jī)中多個(gè)應(yīng)用共享的配置,如果主機(jī)中只有一個(gè)應(yīng)用,那么完全可以拿它做最終的應(yīng)用配置。另外應(yīng)用配置包含主機(jī)配置
注意:在理解時(shí)要記住我們現(xiàn)在的目的是講解通用主機(jī),意思是可以承載你自己定義的服務(wù)的主機(jī),別去想什么mvc controller action 路由之類的
三、核心類
下面分別介紹下主機(jī)中的幾個(gè)核心默認(rèn)實(shí)現(xiàn)類,幾乎每個(gè)類都有對應(yīng)的接口,為了縮短篇幅、便于理解就不講接口了。
3.1、Host
它代表主機(jī),用來宿主(承載)我們應(yīng)用(一個(gè)IHostedService的實(shí)現(xiàn))。
主要包含:日志、主機(jī)和應(yīng)用的生命周期事件、IOC根容器、主機(jī)的選項(xiàng)對象、啟動(dòng)停止/停止方法。
接口中只定義了:IOC根容器 + Start + Stop方法
它在Program.Main中被創(chuàng)建、配置和啟動(dòng)
默認(rèn)實(shí)現(xiàn)Microsoft.Extensions.Hosting.Internal.Host,它是一個(gè)internal的類,這個(gè)主機(jī)將來被啟動(dòng)時(shí):
觸發(fā)主機(jī)的WaitForStartAsync事件
逐一啟動(dòng)主機(jī)內(nèi)部的hostedService
觸發(fā)_applicationLifetime?.NotifyStarted();事件
停止時(shí)就反過來,先逐一停止hostedService,觸發(fā)響應(yīng)事件、最后停止主機(jī)
擴(kuò)展:
因?yàn)槟J(rèn)Host是internal修飾的,所以無法繼承
自定義實(shí)現(xiàn)IHost;(這不說了,你可以隨心所欲)
訂閱主機(jī)和應(yīng)用的生命周期事件(實(shí)現(xiàn)IHostLifetime、IHostApplicationLifetime并添加到IOC容器)
大部分情況下方式2實(shí)現(xiàn)起來更容易也更常見
提一嘴,asp.net core 3.x現(xiàn)在也是使用的這個(gè)默認(rèn)主機(jī),只是在上面做了根web相關(guān)的配置,將在下一篇講解
3.2、HostBuilder
Host的職責(zé)只是完成主機(jī)該有的功能,那么它的創(chuàng)建及配置最好另外定義一個(gè)類HostBuilder,它是Host的創(chuàng)建器(工廠),我們通常
在系統(tǒng)啟動(dòng)時(shí)(Program.Man)先創(chuàng)建HostBuilder,
然后進(jìn)行配置(向IOC容器注冊服務(wù),設(shè)置主機(jī)和應(yīng)用的"配置源"),
最后調(diào)用Build方法生成我們最終的Host
通過接口IHostBuilder源碼可以初略看出它(通過委托的方式)提供以下功能
設(shè)置主機(jī)和應(yīng)用的“配置源”
配置IOC容器本身
想IOC容器添加服務(wù)
創(chuàng)建Host
有個(gè)Properties屬性,是個(gè)字典類型,可以在構(gòu)建Host的多個(gè)步驟中傳遞數(shù)據(jù)
擴(kuò)展:
對于我們使用者來說主要是通過它的方法向內(nèi)部塞入各種委托,以達(dá)到向IOC容器注冊服務(wù)和設(shè)置主機(jī)和應(yīng)用的“配置源”
也可以但估計(jì)很少去實(shí)現(xiàn)主機(jī)的IHostBuilder;繼承HostBuilder意義也不大,因?yàn)樗鼪]有提供抽象和虛方法
默認(rèn)Build流程
初始化主機(jī)配置對象IConfiguration,主要是回調(diào),主機(jī)沒有做其它的
初始化主機(jī)環(huán)境對象_hostingEnvironment
應(yīng)用程序名字從上一步的主機(jī)配置里來
環(huán)境名(開發(fā)?調(diào)試?)從配置里來,若沒有則默認(rèn)是生產(chǎn)模式"Production"
內(nèi)容根也從配置里來,若沒有則是當(dāng)前程序路徑
根據(jù)內(nèi)容跟創(chuàng)建一個(gè)ContentRootFileProvider 實(shí)現(xiàn)類是PhysicalFileProvider
初始化HostBuilderContext,根據(jù)上面的配置和環(huán)境創(chuàng)建這個(gè)上下文(這里只是暫時(shí)用的主機(jī)配置,下面會被替換成應(yīng)用的配置)
初始化應(yīng)用配置
以上面的內(nèi)容根作為配置查找的根(若將來提供物理文件作為配置源時(shí)需要此屬性)
將主機(jī)配置塞入這個(gè)應(yīng)用配置,所以應(yīng)用配置=主機(jī)配置+回調(diào)后的配置
最后將HostBuilderContext的Configuration替換為此配置對象
創(chuàng)建IOC容器
創(chuàng)建ServiceCollection,并將上面的幾個(gè)對象以單利模式放入進(jìn)去
還要放入IHostApplicationLifetime和IHostLifetime和Host
開啟選項(xiàng)模式,注冊日志
回調(diào)configureServicesAction
調(diào)用工廠_serviceProviderFactory創(chuàng)建ServiceProvider
回調(diào)_configureContainerActions
最后返回容器
調(diào)用容器解析并返回Host
3.3、HostBuilder的工廠方法Host.CreateDefaultBuilder
上面有了Host,也有了對應(yīng)的創(chuàng)建器HostBuilder,為啥還要再提供一個(gè)工廠方法呢?
因?yàn)槁氊?zé)分離原則,Host只負(fù)責(zé)承載應(yīng)用并提供容器和設(shè)置配置源;HostBuilder只是負(fù)責(zé)配置并創(chuàng)建Host,盡可能提供一些默認(rèn)值(前提時(shí)將來調(diào)用方未提供那些參數(shù))。此時(shí)我們可以直接用HostBuilder來創(chuàng)建Host并啟動(dòng)它,但別忘了.net core是一個(gè)通用框架,它應(yīng)提供一個(gè)更簡潔的方式來創(chuàng)建最終的Host,因此它提供了靜態(tài)方法Host.CreateDefaultBuilder,它盡可能提供更多的默認(rèn)值,核心任務(wù)如下:
new HostBuilder
設(shè)置程序的當(dāng)前目錄為內(nèi)容根
為主機(jī)配置 設(shè)置 環(huán)境變量作為配置源(只關(guān)注前綴DOTNET_的環(huán)境變量)
為應(yīng)用配置設(shè)置 以“appsettings.json”和“appsettings.{env.EnvironmentName}.json”作為配置源;同時(shí)也將環(huán)境變量加入到應(yīng)用的配置源;最后將命令行參數(shù)加入到配置源
配置日志
若是開發(fā)模式,還會配置依賴注入的范圍驗(yàn)證
四、從使用者的角度來說
通過自定義實(shí)現(xiàn)IHostedService的類來實(shí)現(xiàn)我們的服務(wù),我們的服務(wù)中的類可以
直接使用依賴注入,
也可以通過依賴注入獲取主機(jī)配置和全局應(yīng)用配置對象,或者更方便的是進(jìn)一步使用選項(xiàng)模式
我們也可以注入日志記錄器
由于主機(jī)創(chuàng)建過程的相關(guān)數(shù)據(jù)幾乎都放進(jìn)了IOC容器中,因此我們也可以通過依賴注入拿到
其它...
在Program.man調(diào)用Host.CreateDefaultBuilder,如果需要,提供相應(yīng)的委托來注冊服務(wù)和設(shè)置主機(jī)和應(yīng)用的“配置源”,最好是通過相關(guān)擴(kuò)展方法和自定義擴(kuò)展方法。重點(diǎn)是記得注入我們自己的服務(wù)實(shí)現(xiàn)類
五、總結(jié)
.net core為我們提供了新的承載應(yīng)用(包括但不僅限于asp.net core)的方式-->通用主機(jī),通過它我們可以很容易的在自己的應(yīng)用中使用依賴注入、配置、日志等,你可以發(fā)揮想象實(shí)現(xiàn)很多牛B的框架。
asp.net core 3.x開始默認(rèn)也是使用它來承載的
核心的Host、HostBuilder、Host.CreateDefaultBuilder實(shí)現(xiàn)了通用主機(jī),并提供了擴(kuò)展點(diǎn)
最后我想說如果在.net core上提供一個(gè)默認(rèn)的aop方案就更完美了。
下一篇試試說下asp.net?core是如何承載到通用主機(jī)上的
總結(jié)
以上是生活随笔為你收集整理的.NET Core 3.1通用主机原理及使用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用ASP.NET Core 3.x 构
- 下一篇: 错误使用.Net Redis客户端CSR