回到之前,當(dāng)服務(wù)器在處理如aspx.ashx,等等動(dòng)態(tài)文件的時(shí)候,IIS服務(wù)器將Request請(qǐng)求,交
給aspnet_isapi.dll文件來(lái)處理。
ISAPI是第一個(gè)也是性能最高Request請(qǐng)求報(bào)文最原始的Web請(qǐng)求切入點(diǎn)
aspnet_isapi.dll是一個(gè)非常底層,并且是非托管的win32API,這個(gè)dll非常簡(jiǎn)單,非常高效,并且還被微軟優(yōu)化過(guò)性能。它用來(lái)處理最底層的 指令以及函數(shù)回調(diào),并為高層程序提供了應(yīng)用程序級(jí)別服務(wù)的功能和接口。
當(dāng)aspnet_isapi.dll接收到Request請(qǐng)求的時(shí)候,aspnet_isapi.dll就會(huì)去調(diào)動(dòng)Web服務(wù)器中的.Net Framework,最終加載CLR運(yùn)行環(huán)境,并創(chuàng)建一個(gè)ISAPIRuntime對(duì)象,然后調(diào)用ISAPIRuntime對(duì)象的
PRocessRequest()方法。
ISAPIRuntme.ProcessRequest()方法是進(jìn)入ASP.Net的第一個(gè)入口
ISAPIRuntime.ProcessRequest()方法調(diào)用之后主要做了一件事情,就是將Request的原始請(qǐng)求信息封裝成HttpWorkRequest類,由于HttpWorkRequest類封裝的請(qǐng)求報(bào)文很原始,很復(fù)雜,所以微軟沒(méi)有將其公開(kāi)出來(lái)。接著執(zhí)行StartProcessing()方法,來(lái)創(chuàng)建HttpRuntime對(duì)象并調(diào)用其靜態(tài)方法ProcessRequest()。

圖三 : 如何開(kāi)始ASP.Net
在HttpRuntime對(duì)象調(diào)用其靜態(tài)方法ProcessRequest()之后,我們的Web請(qǐng)求開(kāi)始慢慢進(jìn)入應(yīng)用層級(jí)別,why?
ProcessRequest()這個(gè)方法做了很多事情,具體可以通過(guò)Reflector工具查看,但是大致分為四個(gè)部分:
1.為請(qǐng)求創(chuàng)建了一個(gè)新的HttpContext實(shí)例(這個(gè)對(duì)象就是我們常用的HttpContext上下文對(duì)象),并將HttpWorkRequest中最原始的請(qǐng)求
報(bào)文封裝到HttpContext對(duì)象的HttpRequest對(duì)象中。
2.通過(guò)HttpApplicationFactory(應(yīng)用程序工廠)得到一個(gè)具體的HttpApplication 實(shí)例。
3.調(diào)用HttpApplication.Init()方法來(lái)建立事件請(qǐng)求管道。
4.Init()方法觸發(fā)了HttpApplication.ResumeProcessing()方法來(lái)開(kāi)始執(zhí)行Asp.Net事件請(qǐng)求管道。

圖四 : HttpRuntime,HttpApplication和HttpContext的關(guān)系
Asp.Net事件請(qǐng)求管道詳解
前面說(shuō)Asp.Net是一個(gè)Aop框架,而Asp.Net事件請(qǐng)求管道就是一點(diǎn)。
Asp.Net事件請(qǐng)求管道,是微軟幫程序員提供來(lái)處理Web請(qǐng)求的一些列事件,這些事件是依次執(zhí)行,我們可以通過(guò)在這些事件上注冊(cè)或移除我們自己寫(xiě)的方法,來(lái)修改Web請(qǐng)求執(zhí)行的邏輯。

圖五 : ASP.Net事件請(qǐng)求管道
在第八個(gè)事件的時(shí)候,會(huì)創(chuàng)建請(qǐng)求的頁(yè)面對(duì)象,并轉(zhuǎn)換為IHttpHandler接口。
在第九個(gè)事件到第十一個(gè)事件之間,會(huì)接收到瀏覽器發(fā)過(guò)來(lái)的
sessionId。并先會(huì)將IHttpHandler接口嘗試轉(zhuǎn)換為IRequiresSessionState接口,如果轉(zhuǎn)換成功,Asp.Net會(huì)根據(jù)這個(gè)SessionId到服務(wù)器的Session池中去查找所對(duì)應(yīng)的Session對(duì)象,并將這個(gè)Session對(duì)象賦值到HttpContext對(duì)象的Session屬性。如果嘗試轉(zhuǎn)換為IRequiresSessionState接口不成功,則不加載Session。
在第十一個(gè)事件到第十二個(gè)事件之間,會(huì)調(diào)用在第八個(gè)事件創(chuàng)建的頁(yè)面對(duì)象的ProcessRequest方法。
當(dāng)我們直接使用*.ashx頁(yè)面的時(shí)候,就直接調(diào)用了一個(gè)FrameworkInitialize(),并最終生成響應(yīng)報(bào)文,發(fā)送回客戶端。
當(dāng)我們?cè)谑褂?.aspx頁(yè)面的時(shí)候,它繼承自Page類,而Page類實(shí)現(xiàn)了IHttpHandler接口。

由于Page類實(shí)現(xiàn)了IHttpHandler接口,在ProcessRequest方法中,調(diào)用了FrameworkInitialize()方法。

在FrameworkInitialize()這個(gè)方法內(nèi)部就開(kāi)始打造Asp.Net的頁(yè)面控件樹(shù)(打造html樹(shù)),在其中就調(diào)用了ProcessRequestMain方法,在這個(gè)方法里面就執(zhí)行了整個(gè)Asp.Net頁(yè)面生命周期。
IHttpModules
請(qǐng)求通過(guò)事件管道,一些列的事件被觸發(fā)了,我們可以通過(guò)在Global.asax全局配置文件中看到這些事件。
但是由于這是由程序分配的事件,可能就不是我們想要的。如果我們想要?jiǎng)?chuàng)建一個(gè)能夠復(fù)用的HttpApplication事件管道來(lái)處理Web請(qǐng)求,
我們又想將這些代碼復(fù)用,或者開(kāi)發(fā)成插件的形式。那么我們就可以使用IHttpModules。
IHttpModules配置很簡(jiǎn)單,我們只需要在Web.config里面配置一下就可以了。而具體的HttpModules只需要實(shí)現(xiàn)IHttpModules接口,并注冊(cè)自己的方法就行了。
<?xml version="1.0"?>
<system.web>
<httpModules>
<add name="VEVbHttpModules" type="VEVb.VEVbHttpModules"/>
</httpModules>
</system.web>
</configuration>
Web.config文件的配置
publicclass VEVbHttpModules : IHttpModule
{
public void MyBeginRequest(object sender, EventArgs e)
{
HttpApplication application = sender as HttpApplication;
application.Context.Response.Write("這個(gè)IHttpModule具體類的寫(xiě)法喲!");
}
}
具體的HttpModules類寫(xiě)法
Asp.Net頁(yè)面生命周期詳解
Asp.Net是一個(gè)Aop框架,而Asp.Net事件請(qǐng)求管道體現(xiàn)了Aop思想,而現(xiàn)在我們要說(shuō)的Asp.Net頁(yè)面生命周期也體現(xiàn)Aop思想。
Asp.Net頁(yè)面生命周期的本質(zhì)就是微軟提供給我們程序員修改頁(yè)面控件樹(shù)代碼的一些列事件,我們可以通過(guò)實(shí)現(xiàn)頁(yè)面生命周期的事件方法來(lái)修改控件樹(shù)代碼。
圖六 : ASP.Net頁(yè)面生命周期
當(dāng)ASP.Net執(zhí)行完我們注冊(cè)的生命周期事件方法的時(shí)候,最后會(huì)調(diào)用Render方法,Render方法要求傳入一個(gè)TextWriter文本寫(xiě)出器對(duì)象,并遍歷所有控件樹(shù),調(diào)用每個(gè)控件的Render方法。
所以每一個(gè)控件調(diào)用Render方法之后產(chǎn)生的Html字符串都依次寫(xiě)入到TextWriter對(duì)象。最后ASP.Net將TextWriter中的Html字符串封裝成響應(yīng)報(bào)文,然后發(fā)送回客戶端。
結(jié)束語(yǔ)
在這里,我介紹了一下ASP.Net的整個(gè)處理請(qǐng)求的過(guò)程。但有很多底層的信息,我還沒(méi)有仔細(xì)去觀察過(guò),因此很多細(xì)節(jié)可能還是沒(méi)有注意到。這篇文章可能還是有很多錯(cuò)誤的地方,希望博客園的兄弟姐妹們糾錯(cuò),謝謝。