ASP.NET Core 知多少(3):一張圖理清啟動(dòng)流程

ASP.NET Core知多少系列:總體介紹及目錄

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)建。

ASP.NET Core總體啟動(dòng)流程

這張圖描述了一個(gè)總體的啟動(dòng)流程撮躁,從上圖中我們知道ASP.NET Core應(yīng)用程序的啟動(dòng)主要包含三個(gè)步驟:

  1. CreateDefaultBuilder():創(chuàng)建IWebHostBuilder
  2. Build():IWebHostBuilder負(fù)責(zé)創(chuàng)建IWebHost
  3. Run():?jiǎn)?dòng)IWebHost

所以漱病,ASP.NET Core應(yīng)用的啟動(dòng)本質(zhì)上是啟動(dòng)作為宿主的WebHost對(duì)象。
其主要涉及到兩個(gè)關(guān)鍵對(duì)象IWebHostBuilderIWebHost,它們的內(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()調(diào)用堆棧

從上圖中我們可以看出CreateDefaultBuilder()方法主要干了六件大事:

  1. UseKestrel:使用Kestrel作為Web server僚饭。
  2. UseContentRoot:指定Web host使用的content root(內(nèi)容根目錄),比如Views胧砰。默認(rèn)為當(dāng)前應(yīng)用程序根目錄鳍鸵。
  3. ConfigureAppConfiguration:設(shè)置當(dāng)前應(yīng)用程序配置。主要是讀取 appsettinggs.json 配置文件尉间、開(kāi)發(fā)環(huán)境中配置的UserSecrets偿乖、添加環(huán)境變量和命令行參數(shù) 。
  4. ConfigureLogging:讀取配置文件中的Logging節(jié)點(diǎn)哲嘲,配置日志系統(tǒng)贪薪。
  5. UseIISIntegration:使用IISIntegration 中間件。
  6. 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)用IWebHostBuilderBuild()方法來(lái)完成的光涂。那該方法主要做了哪些事情呢庞萍,我們來(lái)看下面這張【ASP.NET Core啟動(dòng)流程調(diào)用堆棧】中的黃色邊框部分:

ASP.NET Core啟動(dòng)流程調(diào)用堆棧

其核心主要在于WebHost的創(chuàng)建忘闻,又可以劃分為三個(gè)部分:

  1. 構(gòu)建依賴注入容器钝计,初始通用服務(wù)的注冊(cè):BuildCommonService();
  2. 實(shí)例化WebHost:var host = new WebHost(...);
  3. 初始化WebHost,也就是構(gòu)建由中間件組成的請(qǐng)求處理管道:host.Initialize();

3.1. 注冊(cè)初始通用服務(wù)

BuildCommonService方法主要做了兩件事:

  1. 查找HostingStartupAttribute特性以應(yīng)用其他程序集中的啟動(dòng)配置
  2. 注冊(cè)通用服務(wù)
  3. 若配置了啟動(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è)主要部分:

  1. 注冊(cè)Startup中綁定的服務(wù)本鸣;
  2. 配置IServer;
  3. 構(gòu)建管道

請(qǐng)求管道的構(gòu)建主要是借助于IApplicationBuilder硅蹦,相關(guān)類(lèi)圖如下:

請(qǐng)求管道的構(gòu)建

4. 啟動(dòng)WebHost

WebHost的啟動(dòng)主要分為兩步:

  1. 再次確認(rèn)請(qǐng)求管道正確創(chuàng)建
  2. 啟動(dòng)Server以監(jiān)聽(tīng)請(qǐng)求
  3. 啟動(dòng) HostedService
啟動(dòng)WebHost調(diào)用堆棧

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)圖:

IServer類(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)看下具體的接口定義:

IHttpApplication類(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ì)象:

  1. 負(fù)責(zé)創(chuàng)建IWebHost的宿主構(gòu)造器IWebHostBuilder
  2. 代表宿主的IWebHost接口
  3. 用于構(gòu)建請(qǐng)求管道的IApplicationBuilder
  4. 中間件銜接而成的RequestDelegate
  5. 代表Web Server的IServer接口
  6. 貫穿請(qǐng)求處理管道的請(qǐng)求上下文HttpContext
  7. 可以用來(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)信息堂飞。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市绑咱,隨后出現(xiàn)的幾起案子绰筛,更是在濱河造成了極大的恐慌,老刑警劉巖描融,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件别智,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡稼稿,警方通過(guò)查閱死者的電腦和手機(jī)薄榛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)让歼,“玉大人敞恋,你說(shuō)我怎么就攤上這事∧庇遥” “怎么了硬猫?”我有些...
    開(kāi)封第一講書(shū)人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)改执。 經(jīng)常有香客問(wèn)我啸蜜,道長(zhǎng),這世上最難降的妖魔是什么辈挂? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上束亏,老公的妹妹穿的比我還像新娘签则。我一直安慰自己,他們只是感情好拇泣,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布噪叙。 她就那樣靜靜地躺著,像睡著了一般霉翔。 火紅的嫁衣襯著肌膚如雪睁蕾。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,007評(píng)論 1 284
  • 那天债朵,我揣著相機(jī)與錄音子眶,去河邊找鬼。 笑死葱弟,一個(gè)胖子當(dāng)著我的面吹牛壹店,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芝加,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼硅卢,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了藏杖?” 一聲冷哼從身側(cè)響起将塑,我...
    開(kāi)封第一講書(shū)人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蝌麸,沒(méi)想到半個(gè)月后点寥,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡来吩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年敢辩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蔽莱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡戚长,死狀恐怖盗冷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情同廉,我是刑警寧澤仪糖,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布,位于F島的核電站迫肖,受9級(jí)特大地震影響锅劝,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜蟆湖,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一故爵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧帐姻,春花似錦稠集、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至呢铆,卻和暖如春晦鞋,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背棺克。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工悠垛, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人娜谊。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓确买,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親纱皆。 傳聞我的和親對(duì)象是個(gè)殘疾皇子湾趾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容