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是如何承載到通用主機上的
&n