上一篇《asp.net core 3.x 通用主機原理及使用》扯了下3.x中的通用主機,恰好有哥們寫了篇《.NET Core 3.1和WorkerServices構建Windows服務》能夠當作通用主機的案例來看。本篇主要聊下asp.net core 3.x中是如何使用通用主機來承載asp.net core自己的。html
注:我是.net framework 4.x跳到.net core 3.x的,基本看源碼總結的,可能某些地方理解不到位,因此此文只做爲參考別全信哈。web
閱讀前提(參考老A的博客):數據庫
目錄:json
微軟爲咱們提供了一個默認實現(Microsoft.Extensions.Hosting.Internal.Host),它內部主要包含:ioc容器(服務提供器)、生命週期事件處理器、日誌記錄器、和IHostedService集合以及啓動和中止方法。api
用來存儲各類服務對象,這個根容器是全部IHostedService共享的,各個IHostedService也能夠建立主機的「範圍IOC容器」。ioc容器包含微軟爲咱們塞進去的,和咱們本身塞進去的各類服務組件。在主機配置階段微軟會塞入:緩存
因此未來咱們定義的類隨時能夠注入這些對象,這些對象是在HostBuilder中賦值的,請往下看app
未來主機啓動/中止時會觸發回調相應的幾個方法,好比:主機啓動了 應用啓動了 應用中止了,主機中止了。咱們能夠自定義一個事件處理器加入到ioc容器中來實現生命週期事件的訂閱。框架
一個IHostedService的實現類就是一個應用。asp.net core自己就是一個應用。asp.net
觸發相應的生命週期事件、遍歷啓動全部IHostedServiceide
它負責主機的配置和生成。它定義了幾個委託集合,並提供相應的方法容許咱們的代碼向集合中加入本身的委託,這些委託主要是用來:
未來在調用Build生成最終的主機時會:
以上爲通用主機的大體內容,先有個印象,未來須要擴展時在研究源碼
3、通用主機是如何承載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源碼)
先來看個圖:
核心任務是:
因此文章後面部分咱們將這個用來承載asp.net core的通用主機稱爲「Web主機」,把通用主機配置器HostBuilder的包裝類GenericWebHostBuilder稱爲「Web主機配置器」
它包裝了HostBuilder,因此能夠把它理解爲一個特殊的HostBuilder,特殊在它提供web相關的配置api,本質上仍是向通用主機配置對象HostBuilder添加各類服務和配置源
GenericWebHostBuilder有個IConfiguration類型的屬性,能夠把它理解爲跟web相關的配置對象,它會做爲通用主機的配置源,因爲通用主機的配置源又是應用配置的數據源,所以最後:應用配置對象 = 通用主機配置對象 + (web主機配置對象)GenericWebHostBuilder._config + 應用配置對象;
_config在構造函數中被初始化,惟一數據源是以"ASPNETCORE_"爲前綴的環境變量
另外配置對象還在ExecuteHostingStartups被使用到,後面會詳細講
GetSetting、UseSetting這倆方法分別從_config讀取和寫入配置,因此咱們能夠在配置主機時更方便的向配置中加入一些值,也能夠替換一些值來影響一些組件的配置
因此咱們能夠在配置web主機時經過UseSetting來快速設置/替換某些配置值,也能夠在任意能得到GenericWebHostBuilder的地方調用GetSetting方便的獲取配置值
在web主機配置過程當中的多個步驟中常常會使用到這幾個對象,咱們對web主機進行配置時,提供的委託的參數也常常會攜帶者節參數,所以看看這幾個東西是啥。
IWebHostEnvironment
web主機環境相關,它還繼承IHostEnvironment,因此它包含如下內容:
WebHostOptions
web主機選項對象,雖然是這個名字,可是並無應用選項模式,且它是internal修飾的,所以咱們寫代碼一般不會訪問到它,可是它在GenericWebHostBuilder有些做用的
它內部包含根web相關的配置:
WebHostBuilderContext
= IWebHostEnvironment + IConfiguration
private WebHostBuilderContext GetWebHostBuilderContext(HostBuilderContext context)
GenericWebHostBuilder經過這個方法來建立WebHostBuilderContext,web主機配置器內部多個方法都會調用此方法。此方法執行過程大體步驟以下:
因此咱們平時能夠經過多種途徑來配置內容根、web根、應用名、運行環境(開發?生成?)
也能夠在配置web主機時的委託中來經過WebHostBuilderContext來訪問到這些屬性和對應的文件提供器
因爲IHostingEnvironment會以單例註冊到容器,所以咱們未來能夠直接注入HostingEnvironment或者web主機環境對象
調用此方法傳入一個委託,這個委託主要用來配置中間件管道,未來通用主機在啓動時會啓動表明asp.net core的GenericWebHostService,這時咱們這個委託就會被調用。因此配置管道的代碼是在HostBuilder.Build().Run()這個Run階段執行,並非在Build這步
這個方法跟UseStartup(下面會說)是衝突的,意思只能用其中一個,
要了解這個方法的原理,得先說說GenericWebHostServiceOptions,它是一個選項對象,看定義:
1 namespace Microsoft.AspNetCore.Hosting{ 3 internal class GenericWebHostServiceOptions{ 5 public Action<IApplicationBuilder> ConfigureApplication { get; set; } 6 public WebHostOptions WebHostOptions { get; set; } 8 public AggregateException HostingStartupExceptions { get; set; } 10 } 11 }
此對象應用了選項模式,(第5行)ConfigureApplication其實就表明了那個用來配置中間件管道的委託
1 public IWebHostBuilder Configure(Action<WebHostBuilderContext, IApplicationBuilder> configure){ 2 _builder.ConfigureServices((context, services) => { 3 services.Configure<GenericWebHostServiceOptions>(options => { 4 var webhostBuilderContext = GetWebHostBuilderContext(context); 5 options.ConfigureApplication = app => configure(webhostBuilderContext, app); 6 }); 7 }); 8 9 return this; 10 }
因此不管是Startup中的Configre方法,仍是這裏傳入的委託,最終都會以一個委託的形式賦值到GenericWebHostServiceOptions.ConfigureApplication屬性上,而這個委託未來在主機啓動階段被調用,最終實現容許用戶配置中間件管道的目的
爲何要提供兩種配置中間件管道的方式呢?由於直接在Program.main裏配置更簡單,可是封裝性很差,經過單獨的Startup類更清晰。
因此咱們配置中間件管道時除了能夠在Startup.Configre中配置,也能夠直接在Program.main裏配置主機時經過GenericWebHostBuilder.Configure進行配置
未完待續....