1. 引言
對(duì)于ASP.NET Core應(yīng)用程序來(lái)說(shuō)跷坝,我們要記住非常重要的一點(diǎn)是:其本質(zhì)上是一個(gè)獨(dú)立的控制臺(tái)應(yīng)用凉逛,它并不是必需在IIS內(nèi)部托管且并不需要IIS來(lái)啟動(dòng)運(yùn)行(而這正是ASP.NET Core跨平臺(tái)的基石)。ASP.NET Core應(yīng)用程序擁有一個(gè)內(nèi)置的Self-Hosted(自托管)的Web Server(Web服務(wù)器),用來(lái)處理外部請(qǐng)求吵取。
不管是托管還是自托管,都離不開(kāi)Host(宿主)聋溜。在ASP.NET Core應(yīng)用中通過(guò)配置并啟動(dòng)一個(gè)Host來(lái)完成應(yīng)用程序的啟動(dòng)和其生命周期的管理(如下圖所示)谆膳。而Host的主要的職責(zé)就是Web Server的配置和Pilpeline(請(qǐng)求處理管道)的構(gòu)建。
這張圖描述了一個(gè)總體的啟動(dòng)流程撮躁,從上圖中我們知道ASP.NET Core應(yīng)用程序的啟動(dòng)主要包含三個(gè)步驟:
- CreateDefaultBuilder():創(chuàng)建IWebHostBuilder
- Build():IWebHostBuilder負(fù)責(zé)創(chuàng)建IWebHost
- Run():?jiǎn)?dòng)IWebHost
所以漱病,ASP.NET Core應(yīng)用的啟動(dòng)本質(zhì)上是啟動(dòng)作為宿主的WebHost對(duì)象。
其主要涉及到兩個(gè)關(guān)鍵對(duì)象IWebHostBuilder
和IWebHost
,它們的內(nèi)部實(shí)現(xiàn)是ASP.NET Core應(yīng)用的核心所在杨帽。下面我們就結(jié)合源碼并梳理調(diào)用堆棧來(lái)一探究竟漓穿!
2. 宿主構(gòu)造器:IWebHostBuilder
在啟動(dòng)IWebHost
宿主之前,我們需要完成對(duì)IWebHost
的創(chuàng)建和配置注盈。而這一項(xiàng)工作需要借助IWebHostBuilder
對(duì)象來(lái)完成的晃危,ASP.NET Core中提供了默認(rèn)實(shí)現(xiàn)WebHostBuilder
。而WebHostBuilder
是由WebHost的同名工具類(lèi)(Microsoft.AspNetCore命名空間下)中的CreateDefaultBuilder
方法創(chuàng)建的老客。
從上圖中我們可以看出CreateDefaultBuilder()
方法主要干了六件大事:
- UseKestrel:使用Kestrel作為Web server僚饭。
- UseContentRoot:指定Web host使用的content root(內(nèi)容根目錄),比如Views胧砰。默認(rèn)為當(dāng)前應(yīng)用程序根目錄鳍鸵。
- ConfigureAppConfiguration:設(shè)置當(dāng)前應(yīng)用程序配置。主要是讀取 appsettinggs.json 配置文件尉间、開(kāi)發(fā)環(huán)境中配置的UserSecrets偿乖、添加環(huán)境變量和命令行參數(shù) 。
- ConfigureLogging:讀取配置文件中的Logging節(jié)點(diǎn)哲嘲,配置日志系統(tǒng)贪薪。
- UseIISIntegration:使用IISIntegration 中間件。
- UseDefaultServiceProvider:設(shè)置默認(rèn)的依賴注入容器撤蚊。
創(chuàng)建完畢WebHostBuilder
后古掏,通過(guò)調(diào)用UseStartup()
來(lái)指定啟動(dòng)類(lèi),來(lái)為后續(xù)服務(wù)的注冊(cè)及中間件的注冊(cè)提供入口侦啸。
3. 宿主:IWebHost
在ASP.Net Core中定義了IWebHost
用來(lái)表示W(wǎng)eb應(yīng)用的宿主槽唾,并提供了一個(gè)默認(rèn)實(shí)現(xiàn)WebHost
。宿主的創(chuàng)建是通過(guò)調(diào)用IWebHostBuilder
的Build()
方法來(lái)完成的光涂。那該方法主要做了哪些事情呢庞萍,我們來(lái)看下面這張【ASP.NET Core啟動(dòng)流程調(diào)用堆棧】中的黃色邊框部分:
其核心主要在于WebHost的創(chuàng)建忘闻,又可以劃分為三個(gè)部分:
- 構(gòu)建依賴注入容器钝计,初始通用服務(wù)的注冊(cè):BuildCommonService();
- 實(shí)例化WebHost:var host = new WebHost(...);
- 初始化WebHost,也就是構(gòu)建由中間件組成的請(qǐng)求處理管道:host.Initialize();
3.1. 注冊(cè)初始通用服務(wù)
BuildCommonService
方法主要做了兩件事:
- 查找
HostingStartupAttribute
特性以應(yīng)用其他程序集中的啟動(dòng)配置 - 注冊(cè)通用服務(wù)
- 若配置了啟動(dòng)程序集齐佳,則發(fā)現(xiàn)并以
IStartup
類(lèi)型注入到IOC容器中
3.2. 創(chuàng)建IWebHost
public IWebHost Build()
{
//省略部分代碼
var host = new WebHost(
applicationServices,
hostingServiceProvider,
_options,
_config,
hostingStartupErrors);
}
host.Initialize();
return host;
}
3.3. 構(gòu)建請(qǐng)求處理管道
請(qǐng)求管道的構(gòu)建私恬,主要是中間件之間的銜接處理。
而請(qǐng)求處理管道的構(gòu)建炼吴,又包含三個(gè)主要部分:
- 注冊(cè)Startup中綁定的服務(wù)本鸣;
- 配置IServer;
- 構(gòu)建管道
請(qǐng)求管道的構(gòu)建主要是借助于IApplicationBuilder
硅蹦,相關(guān)類(lèi)圖如下:
4. 啟動(dòng)WebHost
WebHost的啟動(dòng)主要分為兩步:
- 再次確認(rèn)請(qǐng)求管道正確創(chuàng)建
- 啟動(dòng)Server以監(jiān)聽(tīng)請(qǐng)求
- 啟動(dòng) HostedService
4.1. 確認(rèn)請(qǐng)求管道的創(chuàng)建
從圖中可以看出荣德,第一步調(diào)用Initialize()
方法主要是取保請(qǐng)求管道的正確創(chuàng)建闷煤。其內(nèi)部主要是對(duì)BuildApplication()
方法的調(diào)用,與我們上面所講WebHost的構(gòu)建環(huán)節(jié)具有相同的調(diào)用堆棧涮瞻。而最終返回的正是由中間件銜接而成的RequestDelegate
類(lèi)型代表的請(qǐng)求管道鲤拿。
4.2. 啟動(dòng)Server
我們先來(lái)看下類(lèi)圖:
從類(lèi)圖中我們可以看出IServer
接口主要定義了一個(gè)只讀的特性集合屬性、一個(gè)啟動(dòng)和停止的方法聲明署咽。在創(chuàng)建宿主構(gòu)造器IWebHostBuilder
時(shí)我們通過(guò)調(diào)用UseKestrel()
方法指定了使用KestrelServer作為默認(rèn)的IServer實(shí)現(xiàn)近顷。其方法申明中接收了一個(gè)IHttpApplication<TContext> application
的參數(shù),從命名來(lái)看艇抠,它代表一個(gè)Http應(yīng)用程序幕庐,我們來(lái)看下具體的接口定義:
其主要定義了三個(gè)方法,第一個(gè)方法用來(lái)創(chuàng)建請(qǐng)求上下文家淤;第二個(gè)方法用來(lái)處理請(qǐng)求异剥;第三個(gè)方法用來(lái)釋放上下文。而至于請(qǐng)求上下文絮重,是用來(lái)攜帶請(qǐng)求和返回響應(yīng)的核心參數(shù)冤寿,其貫穿與整個(gè)請(qǐng)求處理管道之中。ASP.NET Core中提供了默認(rèn)的實(shí)現(xiàn)HostingApplication
青伤,其構(gòu)造函數(shù)接收一個(gè)RequestDelegate _application
(也就是鏈接中間件形成的處理管道)用來(lái)處理請(qǐng)求督怜。
var httpContextFactory = _applicationServices.GetRequiredService<IHttpContextFactory>();
var hostingApp = new HostingApplication(_application, _logger, diagnosticSource, httpContextFactory);
4.3. 啟動(dòng)IHostedService
IHostedService
接口用來(lái)定義后臺(tái)任務(wù),通過(guò)實(shí)現(xiàn)該接口并注冊(cè)到Ioc容器中狠角,它會(huì)隨著ASP.NET Core 程序啟動(dòng)而啟動(dòng)号杠,終止而終止。
5. 總結(jié)
結(jié)合源碼丰歌,通過(guò)對(duì)ASP.NET Core運(yùn)行調(diào)用堆棧的梳理姨蟋,其啟動(dòng)流程的總體脈絡(luò)一目了然,并且了解到主要的幾個(gè)關(guān)鍵對(duì)象:
- 負(fù)責(zé)創(chuàng)建IWebHost的宿主構(gòu)造器IWebHostBuilder
- 代表宿主的IWebHost接口
- 用于構(gòu)建請(qǐng)求管道的IApplicationBuilder
- 中間件銜接而成的RequestDelegate
- 代表Web Server的IServer接口
- 貫穿請(qǐng)求處理管道的請(qǐng)求上下文HttpContext
- 可以用來(lái)注冊(cè)后臺(tái)服務(wù)的IHostedService接口
這一節(jié)就先從總體上對(duì)ASP.NET Core的運(yùn)行原理有個(gè)基本的認(rèn)識(shí)立帖,后續(xù)我們?cè)僖灰恢v解這幾個(gè)核心對(duì)象來(lái)加深理解眼溶。
本文經(jīng)「原本」原創(chuàng)認(rèn)證,作者圣杰晓勇,訪問(wèn)yuanben.io查詢【E5OW396N】獲取授權(quán)信息堂飞。