温故而知新:HttpApplication,HttpModule,HttpContext及Asp.Net页生命周期
IIS在接到一個(gè)新的http請(qǐng)求后,最終會(huì)調(diào)用asp.net_isapi.dll的ISAPI擴(kuò)展(特指IIS6.0環(huán)境,iis7.0的應(yīng)用程序池默認(rèn)為集成方式,相對(duì)有所變化),然后傳遞到httpRuntime Pipe(http運(yùn)行時(shí)管道),Asp.Net這時(shí)才開(kāi)始運(yùn)行(即HttpRunTime是Asp.Net真正的入口),HttpRunTime會(huì)為每個(gè)asp.net應(yīng)用自動(dòng)創(chuàng)建一個(gè)HttpApplication的實(shí)例,而該實(shí)例中又包含以下屬性:
注1
Application -->相當(dāng)于傳統(tǒng)意義上asp時(shí)代的application對(duì)象,通常用于定義一個(gè)asp.net應(yīng)用的全局變量
Context -->HttpContext(上下文)類的實(shí)例【Asp.Net新增的】
Modules -->影響當(dāng)前應(yīng)用程序的HttpModule模塊集合
Request -->類似于asp中的Request對(duì)象,通常用于接收一些特定的值(比如Request.Form或Request.QueryString)
Response -->類似于asp中的Response對(duì)象,通常用于向做頁(yè)面輸出指定內(nèi)容(比如Resonse.Write)
Server -->類似于asp中的Server對(duì)象,通過(guò)它能獲得一些服務(wù)端的信息(比如Server.MapPath)
Session -->類似于asp中的Session對(duì)象
User -->用于獲取用戶認(rèn)證相關(guān)的安全信息
從上面的屬性可以發(fā)現(xiàn):很多其實(shí)在asp年代已在使用,只有Context,Modules,User這三個(gè)是Asp.Net新增的
HttpApplication類除了具備"注1"的幾個(gè)屬性外,還有自己的方法,這里特別提一下Init方法和Dispose方法,這二個(gè)方法均可重載.
它們的調(diào)用時(shí)機(jī)為:
Init方法在Application_Start之后調(diào)用,而Dispose在Application_End之前調(diào)用,另外Application_Start在整個(gè)asp.net應(yīng)用的生命周期內(nèi)只激發(fā)一次(比如IIS啟動(dòng)或網(wǎng)站啟動(dòng)時(shí)),類似的Application_End也只有當(dāng)asp.net應(yīng)用程序關(guān)閉時(shí)被調(diào)用(比如IIS停止或網(wǎng)站停止時(shí))
除了Application_Start和Application_End方法,HttpApplication還提供了以下事件:
這些事件包括前面提到的可重載的Init及Dispose方法,再加上Session對(duì)應(yīng)的Session_Start與Session_End方法,均可直接在Global.ascx.cs中以Application_XXX的形式使用(因?yàn)镚lobal.ascx.cs中定義的類Global本身就是繼承自HttpApplication的)
view source
view sourceprint?| public class Global : System.Web.HttpApplication |
再來(lái)看一下相對(duì)asp而言,新增的Context,Modules,User這三個(gè)屬性
Context:
Context即HttpContext類的實(shí)例,在幾乎整個(gè)aspx頁(yè)面生命周期中,Context上下文一直伴隨著各個(gè)環(huán)節(jié)向下傳遞
所以我們幾乎可以在web應(yīng)用中的任何環(huán)節(jié),用HttpContext.Current來(lái)引用到當(dāng)前的上下文實(shí)例,從HttpContext的定義上,還可以發(fā)現(xiàn)Context本身的屬性中,又可以得到Application,ApplicationInstance,Profile,Response.Request...等對(duì)象的實(shí)例引用
回想一下:
view source
view sourceprint?| /// <summary> |
| ///Handler1 的摘要說(shuō)明 |
| /// </summary> |
| public class Handler1 : IHttpHandler? |
| { |
| ????public void ProcessRequest(HttpContext context) |
| ????{ |
| ????????context.Response.ContentType = "text/plain"; |
| ????????context.Response.Write("Hello World"); |
| ????} |
| ????public bool IsReusable |
| ????{ |
| ????????get |
| ????????{ |
| ????????????return false; |
| ????????} |
| ????} |
| } |
我們?cè)谑褂靡粋€(gè)ashx文件時(shí),ProcessRequest方法便是把當(dāng)前上下文傳遞進(jìn)來(lái),進(jìn)而通過(guò)context得到Response對(duì)象的引用,最終可以向頁(yè)面輸出任何想要的內(nèi)容.
Modules:
每一個(gè)實(shí)現(xiàn)了IHttpModule接口的類,就可以被認(rèn)為是Http模塊組件,可以理解為http請(qǐng)求攔截器,攔截到http請(qǐng)求后,它能修改正在被處理的Context上下文,完事兒之后,再把控制權(quán)交還給管道,如果還有其它模塊,則依次繼續(xù)處理,直到所有Modules集合中的HttpModule都“爽”完為止(注:可憐的http請(qǐng)求就這樣給各個(gè)httpModule輪X了)
asp.net2.0默認(rèn)內(nèi)置了很多HttpModule,從Machine.Config文件中可以發(fā)現(xiàn)以下默認(rèn)的內(nèi)置模塊:
注2
AnonymouseIdentification --為匿名用戶分配一個(gè)臨時(shí)身份
FileAuthorization --驗(yàn)證用戶是否有請(qǐng)求文件的Windows NT許可
FormsAuthentication --窗體身份驗(yàn)證模塊(如果沒(méi)有這個(gè)模塊,asp.net就無(wú)法以用戶名/密碼[即FOrms]方式驗(yàn)證)
OutputCache --輸出緩存模塊
PassportAuthentication --PassPort驗(yàn)證模塊
Profile --用戶配置模塊(如果沒(méi)有它,asp.net中就無(wú)法使用Profile)
RoleManager --角色管理
SessionSate --會(huì)話狀態(tài)模塊
UrlAuthorization --基于URL的身份驗(yàn)證模塊
WindowsAuthentication --Windows和IIS身份驗(yàn)證模塊
User:
如果您使用過(guò)asp.net2.0內(nèi)置的Membership/Role機(jī)制來(lái)進(jìn)行訪問(wèn)認(rèn)證,就會(huì)對(duì)User對(duì)象感到很熟悉,比如:
view source
view sourceprint?| if (HttpContext.Current.User.Identity.IsAuthenticated) |
| { |
| ?//用戶登錄過(guò)了... |
| } |
我們常用它來(lái)判斷當(dāng)前瀏覽用戶的登錄狀態(tài),關(guān)于User類的更詳細(xì)定義,可參見(jiàn)MSDN
生命周期:
最后再來(lái)回顧一下Asp.Net中Page頁(yè)的生命周期,Page中定義了幾個(gè)事件:
總體上講:一個(gè)ASPX頁(yè)面被請(qǐng)求時(shí),最終的生命周期就是由Page中定義的上述事件(還有一些可重載的回調(diào)方法)以及以前提到的HttpApplication類中定義的事件(以相應(yīng)的回調(diào)方法)共同觸發(fā)或調(diào)用,最終疊加形成的一連串處理過(guò)程。
如果先不考慮HttpApplication中的事件處理方法(即不考慮我們?cè)贕lobal.ascx.cs中定義的Application_XXX處理方法),Page中的事件(方法)常規(guī)觸發(fā)(調(diào)用)順序?yàn)?#xff1a;
01.Page_PreInit
02.Page_Init
03.Page_InitComplete
04.Page_PreLoad
05.Page_Load
06.Page_LoadComplete
07.Page_PreRender
08.Page_SaveStateComplete
09.Page_Unload
這是在Page頁(yè)面未回發(fā),且不考慮頁(yè)面子控件的前提下正常的順序,如果加入頁(yè)面回發(fā)(比如在頁(yè)面中放一個(gè)asp:Button,然后在Button的Click回發(fā)事件中加入處理函數(shù))后,順序稍微有些變化:
01.Page_PreInit
02.Page_Init
03.Page_InitComplete
04.Page_PreLoad
05.Page_Load
06.Button1_Click
07.Page_LoadComplete
08.Page_PreRender
09.Page_SaveStateComplete
10.Page_Unload
不同的地方在于:回發(fā)事件Button1_Click在Page_Load后被觸發(fā).
最后再把HttpApplication的事件考慮進(jìn)來(lái),看下疊加后的順序,不過(guò)先別著急,我們先來(lái)看一種特殊情況,如果一個(gè)asp.net應(yīng)用根目錄下未設(shè)置默認(rèn)頁(yè),這時(shí)直接瀏覽根目錄,比如http://localhost:2345/ 時(shí),Globl.ascx.cs中定義的Application_XXX方法的調(diào)用順序如下:
2011-05-03 15:01:39 413?Application_Start
2011-05-03 15:01:39 491?Init
2011-05-03 15:01:39 491?Application_BeginRequest
2011-05-03 15:01:39 506?Application_AuthenticateRequest
2011-05-03 15:01:39 506?Application_PostAuthenticateRequest
2011-05-03 15:01:39 506?Application_AuthorizeRequest
2011-05-03 15:01:39 522?Application_PostAuthorizeRequest
2011-05-03 15:01:39 522?Application_ResolveRequestCache
2011-05-03 15:01:39 522?Application_PostResolveRequestCache
2011-05-03 15:01:39 522?Application_PostMapRequestHandler
2011-05-03 15:01:39 522?Application_AcquireRequestState
2011-05-03 15:01:39 537?Application_PostAcquireRequestState
2011-05-03 15:01:39 537?Application_PreRequestHandlerExecute
2011-05-03 15:01:39 553?Application_Error
2011-05-03 15:01:39 553?Application_EndRequest
2011-05-03 15:01:39 569?Application_PreSendRequestHeaders
2011-05-03 15:01:39 569?Application_PreSendRequestContent
可以看到會(huì)觸發(fā)Application_Error事件,即HttpRuntime認(rèn)為這是一個(gè)錯(cuò)誤.
緊接著再瀏覽一個(gè)實(shí)際存在的頁(yè)面,如果這時(shí)應(yīng)用程序有嚴(yán)重錯(cuò)誤,導(dǎo)致Application關(guān)閉(比如web.config配置錯(cuò)誤),調(diào)用的順序如下:
2011-05-03 15:03:47 704?Application_BeginRequest
2011-05-03 15:03:47 704?Application_AuthenticateRequest
2011-05-03 15:03:47 766?Application_PostAuthenticateRequest
2011-05-03 15:03:47 766?Application_AuthorizeRequest
2011-05-03 15:03:47 766?Application_PostAuthorizeRequest
2011-05-03 15:03:47 766?Application_ResolveRequestCache
2011-05-03 15:03:47 783?Application_PostResolveRequestCache
2011-05-03 15:03:48 667?Application_PostMapRequestHandler
2011-05-03 15:03:48 667?Application_AcquireRequestState
2011-05-03 15:03:48 683?Application_PostAcquireRequestState
2011-05-03 15:03:48 698?Application_PreRequestHandlerExecute
2011-05-03 15:03:48 745?Page_PreInit
2011-05-03 15:04:02 903?Page_Unload
2011-05-03 15:04:02 903?Application_Error
2011-05-03 15:04:02 918?Application_EndRequest
2011-05-03 15:04:02 996?Application_PreSendRequestHeaders
2011-05-03 15:04:02 996?Application_PreSendRequestContent
2011-05-03 15:04:03 371?Application_Disposed
2011-05-03 15:04:03 371?Dispose
2011-05-03 15:04:03 386?Application_End
對(duì)比剛才的順序,會(huì)發(fā)現(xiàn)Application_Start及Init沒(méi)有再次被調(diào)用,也印證了文章前面提到的一些結(jié)論(Application_Start在整個(gè)asp.net應(yīng)用生命周期內(nèi)只觸發(fā)一次),而且從最后的三個(gè)輸出能知道:應(yīng)用程序關(guān)閉時(shí)Application_Disposed,Dispose,Application_End按順序調(diào)用.
再"重新"瀏覽(指web Server重啟)一下正常訪問(wèn)的頁(yè)面,在不出錯(cuò)也不回發(fā)的情況下,順序如下:
2011-05-03 15:08:11 513?Application_Start
2011-05-03 15:08:11 591?Init
2011-05-03 15:08:11 591?Application_BeginRequest
2011-05-03 15:08:11 591?Application_AuthenticateRequest
2011-05-03 15:08:11 591?Application_PostAuthenticateRequest
2011-05-03 15:08:11 606?Application_AuthorizeRequest
2011-05-03 15:08:11 606?Application_PostAuthorizeRequest
2011-05-03 15:08:11 606?Application_ResolveRequestCache
2011-05-03 15:08:11 606?Application_PostResolveRequestCache
2011-05-03 15:08:11 622?Application_PostMapRequestHandler
2011-05-03 15:08:11 637?Application_EndRequest
2011-05-03 15:08:11 637?Application_PreSendRequestHeaders
2011-05-03 15:08:11 637?Application_PreSendRequestContent
2011-05-03 15:08:11 637?Application_BeginRequest
2011-05-03 15:08:11 637?Application_AuthenticateRequest
2011-05-03 15:08:11 653?Application_PostAuthenticateRequest
2011-05-03 15:08:11 653?Application_AuthorizeRequest
2011-05-03 15:08:11 653?Application_PostAuthorizeRequest
2011-05-03 15:08:11 653?Application_ResolveRequestCache
2011-05-03 15:08:11 653?Application_PostResolveRequestCache
2011-05-03 15:08:11 653?Application_PostMapRequestHandler
2011-05-03 15:08:11 653?Session_Start
2011-05-03 15:08:11 653?Application_AcquireRequestState
2011-05-03 15:08:11 653?Application_PostAcquireRequestState
2011-05-03 15:08:11 653?Application_PreRequestHandlerExecute
2011-05-03 15:08:11 669?Page_PreInit
2011-05-03 15:08:11 684?Page_Init
2011-05-03 15:08:11 684?Page_InitComplete
2011-05-03 15:08:11 684?Page_PreLoad
2011-05-03 15:08:11 684?Page_Load
2011-05-03 15:08:11 684?Page_LoadComplete
2011-05-03 15:08:11 684?Page_PreRender
2011-05-03 15:08:11 684?Page_SaveStateComplete
2011-05-03 15:08:11 700?Page_Unload
2011-05-03 15:08:11 700?Application_PostRequestHandlerExecute
2011-05-03 15:08:11 700?Application_ReleaseRequestState
2011-05-03 15:08:11 700?Application_PostReleaseRequestState
2011-05-03 15:08:11 700?Application_UpdateRequestCache
2011-05-03 15:08:11 700?Application_PostUpdateRequestCache
2011-05-03 15:08:11 700?Application_EndRequest
2011-05-03 15:08:11 700?Application_PreSendRequestHeaders
2011-05-03 15:08:11 700?Application_PreSendRequestContent
2011-05-03 15:08:11 793?Application_BeginRequest
2011-05-03 15:08:11 793?Application_AuthenticateRequest
2011-05-03 15:08:11 793?Application_PostAuthenticateRequest
2011-05-03 15:08:11 793?Application_AuthorizeRequest
2011-05-03 15:08:11 793?Application_PostAuthorizeRequest
2011-05-03 15:08:11 793?Application_ResolveRequestCache
2011-05-03 15:08:11 793?Application_PostResolveRequestCache
2011-05-03 15:08:11 809?Application_PostMapRequestHandler
2011-05-03 15:08:11 809?Application_AcquireRequestState
2011-05-03 15:08:11 809?Application_PostAcquireRequestState
2011-05-03 15:08:11 809?Application_PreRequestHandlerExecute
2011-05-03 15:08:11 825?Application_PostRequestHandlerExecute
2011-05-03 15:08:11 825?Application_ReleaseRequestState
2011-05-03 15:08:11 840?Application_PostReleaseRequestState
2011-05-03 15:08:11 949?Application_UpdateRequestCache
2011-05-03 15:08:11 949?Application_PostUpdateRequestCache
2011-05-03 15:08:11 965?Application_EndRequest
2011-05-03 15:08:11 981?Application_PreSendRequestHeaders
2011-05-03 15:08:11 981?Application_PreSendRequestContent
哇!原來(lái)一個(gè)頁(yè)面訪問(wèn)下來(lái),會(huì)調(diào)用到這么多的方法,怪不得很多高并發(fā)的大型網(wǎng)站,通常都要自己寫(xiě)一個(gè)精減的HttpHandler用來(lái)取代Page做為基類,以期望獲得更好的性能
更準(zhǔn)確的頁(yè)面生命周期解釋,請(qǐng)查閱下面的文檔,這是msdn官方網(wǎng)站對(duì)于Asp.Net頁(yè)面生命周期的權(quán)威解釋
文中源碼
總結(jié)
以上是生活随笔為你收集整理的温故而知新:HttpApplication,HttpModule,HttpContext及Asp.Net页生命周期的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 庆元旦黑板报文字资料(庆元旦主题黑板报内
- 下一篇: ASP.NET页面级别的事务