您好,登錄后才能下訂單哦!
這篇文章將為大家詳細(xì)講解有關(guān)asp.net MVC應(yīng)用程序生命周期的示例分析,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
我們都知道,在ASP.NET MVC框架出現(xiàn)之前,我們大部分開發(fā)所使用的框架都是ASP.NET WebForm.其實(shí)不管是MVC還是WebForm,在請(qǐng)求處理機(jī)制上,大部分是相同的。這涉及到IIS對(duì)請(qǐng)求的處理,涉及的知識(shí)較多,我們就不做介紹了,下次有機(jī)會(huì)我寫一篇專文。我們從HttpApplication說起。先看看微軟官方是怎么定義HttpApplication的:
定義 ASP.NET 應(yīng)用程序中的所有應(yīng)用程序?qū)ο蠊灿械姆椒ā傩院褪录?。此類是用戶?Global.asax 文件中所定義的應(yīng)用程序的基類。
可能我翻譯不是很準(zhǔn)確,原文連接在這里:https://msdn.microsoft.com/en-us/library/system.web.httpapplication(v=vs.110).aspx
微軟官方文檔中Remark里有這么一段話:HttpApplication 類的實(shí)例是在 ASP.NET 基礎(chǔ)結(jié)構(gòu)中創(chuàng)建的,而不是由用戶直接創(chuàng)建的。使用 HttpApplication 類的一個(gè)實(shí)例來處理其生存期中收到的眾多請(qǐng)求。但是,它每次只能處理一個(gè)請(qǐng)求。這樣,成員變量才可用于存儲(chǔ)針對(duì)每個(gè)請(qǐng)求的數(shù)據(jù)。
意思就是說ASP.NET應(yīng)用程序,不管是MVC還是WebForm,最終都會(huì)到達(dá)一個(gè)HttpApplication類的實(shí)例。HttpApplication是整個(gè)ASP.NET基礎(chǔ)架構(gòu)的核心,負(fù)責(zé)處理分發(fā)給他的請(qǐng)求。HttpApplication處理請(qǐng)求的周期是一個(gè)復(fù)雜的過程,在整個(gè)過程中,不同階段會(huì)觸發(fā)相映的事件。我們可以注冊(cè)相應(yīng)的事件,將處理邏輯注入到HttpApplication處理請(qǐng)求的某個(gè)階段。在HttpApplication這個(gè)類中定義了19個(gè)事件來處理到達(dá)HttpApplication實(shí)例的請(qǐng)求。就是說不管MVC還是WebForm,最終都要經(jīng)過這19個(gè)事件的處理,那么除了剛才說的MVC和WebFrom在請(qǐng)求處理機(jī)制上大部分都是相同的,不同之處在哪呢?他們是從哪里開始分道揚(yáng)鑣的呢?我們猜想肯定就在這19個(gè)方法中。我們繼續(xù)往下看。
我們來看看這19個(gè)事件:
應(yīng)用程序按照以下順序執(zhí)行由 global.asax 文件中定義的模塊或用戶代碼處理的事件:
事件名稱: | 簡單描述: |
BeginRequest | 在 ASP.NET 響應(yīng)請(qǐng)求時(shí)作為 HTTP 執(zhí)行管線鏈中的第一個(gè)事件發(fā)生 |
AuthenticateRequest | 當(dāng)安全模塊已建立用戶標(biāo)識(shí)時(shí)發(fā)生。注:AuthenticateRequest 事件發(fā)出信號(hào)表示配置的身份驗(yàn)證機(jī)制已對(duì)當(dāng)前請(qǐng)求進(jìn)行了身份驗(yàn)證。預(yù)訂 AuthenticateRequest 事件可確保在處理附加的模塊或事件處理程序之前對(duì)請(qǐng)求進(jìn)行身份驗(yàn)證 |
PostAuthenticateRequest | 當(dāng)安全模塊已建立用戶標(biāo)識(shí)時(shí)發(fā)生。PostAuthenticateRequest 事件在 AuthenticateRequest 事件發(fā)生之后引發(fā)。預(yù)訂 PostAuthenticateRequest 事件的功能可以訪問由 PostAuthenticateRequest 處理的任何數(shù)據(jù) |
AuthorizeRequest | 當(dāng)安全模塊已驗(yàn)證用戶授權(quán)時(shí)發(fā)生。AuthorizeRequest 事件發(fā)出信號(hào)表示 ASP.NET 已對(duì)當(dāng)前請(qǐng)求進(jìn)行了授權(quán)。預(yù)訂 AuthorizeRequest 事件可確保在處理附加的模塊或事件處理程序之前對(duì)請(qǐng)求進(jìn)行身份驗(yàn)證和授權(quán) |
PostAuthorizeRequest | 在當(dāng)前請(qǐng)求的用戶已獲授權(quán)時(shí)發(fā)生。PostAuthorizeRequest 事件發(fā)出信號(hào)表示 ASP.NET 已對(duì)當(dāng)前請(qǐng)求進(jìn)行了授權(quán)。預(yù)訂PostAuthorizeRequest 事件可確保在處理附加的模塊或處理程序之前對(duì)請(qǐng)求進(jìn)行身份驗(yàn)證和授權(quán) |
ResolveRequestCache | 當(dāng) ASP.NET 完成授權(quán)事件以使緩存模塊從緩存中為請(qǐng)求提供服務(wù)時(shí)發(fā)生,從而跳過事件處理程序(例如某個(gè)頁或 XML Web services)的執(zhí)行 |
PostResolveRequestCache | 在 ASP.NET 跳過當(dāng)前事件處理程序的執(zhí)行并允許緩存模塊滿足來自緩存的請(qǐng)求時(shí)發(fā)生。)在 PostResolveRequestCache 事件之后、PostMapRequestHandler 事件之前創(chuàng)建一個(gè)事件處理程序(對(duì)應(yīng)于請(qǐng)求 URL 的頁 |
PostMapRequestHandler | 在 ASP.NET 已將當(dāng)前請(qǐng)求映射到相應(yīng)的事件處理程序時(shí)發(fā)生。 |
AcquireRequestState | 當(dāng) ASP.NET 獲取與當(dāng)前請(qǐng)求關(guān)聯(lián)的當(dāng)前狀態(tài)(如會(huì)話狀態(tài))時(shí)發(fā)生。 |
PostAcquireRequestState | 在已獲得與當(dāng)前請(qǐng)求關(guān)聯(lián)的請(qǐng)求狀態(tài)(例如會(huì)話狀態(tài))時(shí)發(fā)生。 |
PreRequestHandlerExecute | 恰好在 ASP.NET 開始執(zhí)行事件處理程序(例如,某頁或某個(gè) XML Web services)前發(fā)生。 |
PostRequestHandlerExecute | 在 ASP.NET 事件處理程序(例如,某頁或某個(gè) XML Web service)執(zhí)行完畢時(shí)發(fā)生。 |
ReleaseRequestState | 在 ASP.NET 執(zhí)行完所有請(qǐng)求事件處理程序后發(fā)生。該事件將使?fàn)顟B(tài)模塊保存當(dāng)前狀態(tài)數(shù)據(jù)。 |
PostReleaseRequestState | 在 ASP.NET 已完成所有請(qǐng)求事件處理程序的執(zhí)行并且請(qǐng)求狀態(tài)數(shù)據(jù)已存儲(chǔ)時(shí)發(fā)生。 |
UpdateRequestCache | 當(dāng) ASP.NET 執(zhí)行完事件處理程序以使緩存模塊存儲(chǔ)將用于從緩存為后續(xù)請(qǐng)求提供服務(wù)的響應(yīng)時(shí)發(fā)生。 |
PostUpdateRequestCache | 在 ASP.NET 完成緩存模塊的更新并存儲(chǔ)了用于從緩存中為后續(xù)請(qǐng)求提供服務(wù)的響應(yīng)后,發(fā)生此事件。 |
LogRequest | 在 ASP.NET 完成緩存模塊的更新并存儲(chǔ)了用于從緩存中為后續(xù)請(qǐng)求提供服務(wù)的響應(yīng)后,發(fā)生此事件。 僅在 IIS 7.0 處于集成模式并且 .NET Framework 至少為 3.0 版本的情況下才支持此事件 |
PostLogRequest | 在 ASP.NET 處理完 LogRequest 事件的所有事件處理程序后發(fā)生。 僅在 IIS 7.0 處于集成模式并且 .NET Framework 至少為 3.0 版本的情況下才支持此事件。 |
EndRequest | 在 ASP.NET 響應(yīng)請(qǐng)求時(shí)作為 HTTP 執(zhí)行管線鏈中的最后一個(gè)事件發(fā)生。 在調(diào)用 CompleteRequest 方法時(shí)始終引發(fā) EndRequest 事件。 |
對(duì)于一個(gè)ASP.NET應(yīng)用程序來說,HttpApplication派生與Global.aspx(可以看看我們創(chuàng)建的應(yīng)用程序都有一個(gè)Global.aspx文件),我們可以在Global.aspx文件中對(duì)HttpApplication的請(qǐng)求進(jìn)行定制即注入這19個(gè)事件中的某個(gè)事件進(jìn)行邏輯處理操作。在Global.aspx中我們按照"Application_{Event Name}"這樣的方法命名進(jìn)行事件注冊(cè)。
Event Name就是上面19個(gè)事件的名稱。比如Application_EndRequest就用于處理Application的EndRequest事件。
HttpModule
ASP.NET擁有一個(gè)高度可擴(kuò)展的引擎,并且能夠處理對(duì)于不同資源類型的請(qǐng)求。這就是HttpModule。當(dāng)一個(gè)請(qǐng)求轉(zhuǎn)入ASP.net管道時(shí),最終負(fù)責(zé)處理請(qǐng)求的是與資源相匹配的HttpHandler對(duì)象,但是在HttpHandler進(jìn)行處理之前,ASP.NET先會(huì)加載并初始化所有配置的HttpModule對(duì)象。HttpModule初始化的時(shí)候,會(huì)將一些回調(diào)事件注入到HttpApplication相應(yīng)的事件中。所有的HttpModule都實(shí)現(xiàn)了IHttpModule接口,該接口有一個(gè)有一個(gè)Init方法。
public interface IHttpModule { // Methods void Dispose(); void Init(HttpApplication context); }
看到Init方法呢接受一個(gè)HttpApplication對(duì)象,有了這個(gè)對(duì)象就很容易注冊(cè)HttpApplication中19個(gè)事件中的某個(gè)事件了。這樣當(dāng)HttpApplication對(duì)象執(zhí)行到某個(gè)事件的時(shí)候自然就會(huì)出發(fā)。
HttpHandler
對(duì)于不同的資源類型的請(qǐng)求,ASP.NET會(huì)加載不同的HttpHandler來處理。所有的HttpHandler都實(shí)現(xiàn)了IhttpHandler接口。
public interface IHttpHandler { // Methods void ProcessRequest(HttpContext context); // Properties bool IsReusable { get; } }
我們看到該接口有一個(gè)方法ProcessRequest,顧名思義這個(gè)方法就是主要用來處理請(qǐng)求的。所以說每一個(gè)請(qǐng)求最終分發(fā)到自己相應(yīng)的HttpHandler來處理該請(qǐng)求。
ASP.NET MVC 運(yùn)行機(jī)制
好了,上面說了那么多,其實(shí)都是給這里做鋪墊呢。終于到正題了。先看看下面這張圖,描述了MVC的主要經(jīng)歷的管道事件:
上圖就是一個(gè)完整的mvc應(yīng)用程序的一個(gè)http請(qǐng)求到響應(yīng)的整個(gè)兒所經(jīng)歷的流程。從UrlRoutingModule攔截請(qǐng)求到最終ActionResult執(zhí)行ExecuteResult方法生成響應(yīng)。
下面我們就來詳細(xì)講解一下這些過程都做了些什么。
UrlRoutingModule
MVC應(yīng)用程序的入口UrlRoutingModule
首先發(fā)起一個(gè)請(qǐng)求,我們前面講到ASP.NET 會(huì)加載一個(gè)HttpModule對(duì)象的初始化事件Init,而所有的HttpModule對(duì)象都實(shí)現(xiàn)了IHttpModule接口。我們看看UrlRoutingModule的實(shí)現(xiàn):
從上圖中我們看到UrlRoutingModule實(shí)現(xiàn)了接口IHttpModule,當(dāng)一個(gè)請(qǐng)求轉(zhuǎn)入ASP.NET管道時(shí),就會(huì)加載 UrlRoutingModule對(duì)象的Init()方法。
那么為什么偏偏是UrlRoutingModule被加載初始化了呢?為什么不是別的HttpModule對(duì)象呢?帶著這個(gè)疑問我們繼續(xù)。
在ASP.NET MVC中,最核心的當(dāng)屬“路由系統(tǒng)”,而路由系統(tǒng)的核心則源于一個(gè)強(qiáng)大的System.Web.Routing.dll組件。System.Web.Routing.dll 不是MVC所特有的,但是MVC框架和它是密不可分的。
首先,我們要了解一下UrlRoutingModule是如何起作用的。
(1)IIS網(wǎng)站的配置可以分為兩個(gè)塊:全局 Web.config 和本站 Web.config。Asp.Net Routing屬于全局性的,所以它配置在全局Web.Config 中,我們可以在如下路徑中找到:“C\Windows\Microsoft.NET\Framework\版本號(hào)\Config\Web.config“,我提取部分重要配置大家看一下:
<httpModules> <add name="OutputCache" type="System.Web.Caching.OutputCacheModule" /> <add name="Session" type="System.Web.SessionState.SessionStateModule" /> <add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" /> <add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" /> <add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" /> <add name="RoleManager" type="System.Web.Security.RoleManagerModule" /> <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" /> <add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" /> <add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" /> <add name="Profile" type="System.Web.Profile.ProfileModule" /> <add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> <add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" /> <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" /> <add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/> </httpModules>
大家看到?jīng)]有,我上面標(biāo)紅的那一行:<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
UrlRoutingModule并不是MVC特有的,這是一個(gè)全局配置,就是說所有的ASP.NET請(qǐng)求都會(huì)到達(dá)這里,所以該Module還不能最終決定是MVC還是WebForm請(qǐng)求。但是也是至關(guān)重要的地方。
(2)通過在全局Web.Config中注冊(cè) System.Web.Routing.UrlRoutingModule,IIS請(qǐng)求處理管道接到請(qǐng)求后,就會(huì)加載 UrlRoutingModule類型的Init()方法。其源碼入下:
[TypeForwardedFrom("System.Web.Routing, Version=3.5.0.0, Culture=Neutral, PublicKeyToken=31bf3856ad364e35")] public class UrlRoutingModule : IHttpModule { // Fields private static readonly object _contextKey = new object(); private static readonly object _requestDataKey = new object(); private RouteCollection _routeCollection; // Methods protected virtual void Dispose() { } protected virtual void Init(HttpApplication application) { if (application.Context.Items[_contextKey] == null) { application.Context.Items[_contextKey] = _contextKey; application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); } } private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) { HttpApplication application = (HttpApplication) sender; HttpContextBase context = new HttpContextWrapper(application.Context); this.PostResolveRequestCache(context); } [Obsolete("This method is obsolete. Override the Init method to use the PostMapRequestHandler event.")] public virtual void PostMapRequestHandler(HttpContextBase context) { } public virtual void PostResolveRequestCache(HttpContextBase context) { RouteData routeData = this.RouteCollection.GetRouteData(context); if (routeData != null) { IRouteHandler routeHandler = routeData.RouteHandler; if (routeHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0])); } if (!(routeHandler is StopRoutingHandler)) { RequestContext requestContext = new RequestContext(context, routeData); context.Request.RequestContext = requestContext; IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); if (httpHandler == null) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() })); } if (httpHandler is UrlAuthFailureHandler) { if (!FormsAuthenticationModule.FormsAuthRequired) { throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3")); } UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, this); } else { context.RemapHandler(httpHandler); } } } } [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] void IHttpModule.Dispose() { this.Dispose(); } [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] void IHttpModule.Init(HttpApplication application) { this.Init(application); } // Properties public RouteCollection RouteCollection { get { if (this._routeCollection == null) { this._routeCollection = RouteTable.Routes; } return this._routeCollection; } [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")] set { this._routeCollection = value; } } }
看看上面的UrlRoutingModule源碼里面是怎么實(shí)現(xiàn)Init方法的,Init()方法里面我標(biāo)注紅色的地方:
application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
這一步至關(guān)重要哈,看到?jīng)]有,就是對(duì)我們?cè)贖ttpApplication那19個(gè)事件中的PostResolveRequestCache事件的注冊(cè)。注冊(cè)的方法是OnApplicationPostResolveRequestCache事件。也就是說HttpApplication對(duì)象在執(zhí)行到PostResolveRequestCache這個(gè)事件的時(shí)候,就會(huì)執(zhí)行OnApplicationPostResolveRequestCache事件。決定是MVC機(jī)制處理請(qǐng)求的關(guān)鍵所在就是OnApplicationPostResolveRequestCache事件。
從源碼中我們看出,OnApplicationPostResolveRequestCache事件執(zhí)行的時(shí)候,最終執(zhí)行了PostResolveRequestCache這個(gè)方法。最關(guān)鍵的地方呢就在這里了。
當(dāng)請(qǐng)求到達(dá)UrlRoutingModule的時(shí)候,UrlRoutingModule取出請(qǐng)求中的Controller、Action等RouteData信息,與路由表中的所有規(guī)則進(jìn)行匹配,若匹配,把請(qǐng)求交給IRouteHandler,即MVCRouteHandler。我們可以看下UrlRoutingModule的源碼來看看,以下是幾句核心的代碼:
我們?cè)俜治鲆幌逻@個(gè)方法的源碼:
public virtual void PostResolveRequestCache(HttpContextBase context) { // 通過RouteCollection的靜態(tài)方法GetRouteData獲取到封裝路由信息的RouteData實(shí)例 RouteData routeData = this.RouteCollection.GetRouteData(context); if (routeData != null) { // 再從RouteData中獲取MVCRouteHandler IRouteHandler routeHandler = routeData.RouteHandler; ...... if (!(routeHandler is StopRoutingHandler)) { ...... // 調(diào)用 IRouteHandler.GetHttpHandler(),獲取的IHttpHandler 類型實(shí)例,它是由 IRouteHandler.GetHttpHandler獲取的,這個(gè)得去MVC的源碼里看 IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); ...... // 合適條件下,把之前將獲取的IHttpHandler 類型實(shí)例 映射到IIS HTTP處理管道中 context.RemapHandler(httpHandler); } } }
看到了吧,通過路由規(guī)則,返回的不為空,說明匹配正確,關(guān)于路由規(guī)則的匹配,說起來也不短,這里就不大幅介紹,有時(shí)間下次再開篇詳解路由機(jī)制。匹配成功后,返回一個(gè)RouteData類型的對(duì)象,RouteData對(duì)象都有些什么屬性呢?看看這行源碼: IRouteHandler routeHandler = routeData.RouteHandler;或者看源碼我們知道,RouteDate有一個(gè)RouteHandler屬性。
那么UrlRouting Module是如何選擇匹配規(guī)則的呢?
我們看看我們新建的MVC應(yīng)用程序,在App_Start文件夾下面有一個(gè)RouteConfig.cs類,這個(gè)類的內(nèi)容如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using System.Web.Routing; namespace ApiDemo { public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } } }
我們?cè)谶@個(gè)類里面,主要是給路由表添加路由規(guī)則。在看看上面的UrlRoutingModule類,里面有一個(gè)RoutCollection屬性,所以UrlRoutingModule能夠獲取路由表中的所有規(guī)則,這里值得注意的是,路由規(guī)則的匹配是有順序的,如果有多個(gè)規(guī)則都能夠匹配,UrlRoutingModule至選擇第一個(gè)匹配的規(guī)則就返回,不再繼續(xù)往下匹配了。相反的如果一個(gè)請(qǐng)求,沒有匹配到任何路由,那么該請(qǐng)求就不會(huì)被處理。
這里返回的RouteData里的RouteHandler就是MVCRouteHandler。為什么呢?那我們繼續(xù)往下看RouteHandler。
RouteHandler
生成MvcHander
在上面路由匹配的過程中,與匹配路由相關(guān)聯(lián)的MvcRouteHandler ,MvcRouteHandler 實(shí)現(xiàn)了IRouteHandler 接口。MvcRouteHandler 主要是用來獲取對(duì)MvcHandler的引用。MvcHandler實(shí)現(xiàn)了IhttpHandler接口。
MVCRouteHandler的作用是用來生成實(shí)現(xiàn)IHttpHandler接口的MvcHandler。而我們前面說過最終處理請(qǐng)求的都是相對(duì)應(yīng)的HttpHandler。那么處理MVC請(qǐng)求的自然就是這個(gè)MvcHandler。所以這里返回MvcRouteHandler至關(guān)重要:
那么,MvcRouteHandler從何而來呢?眾所周知,ASP.NET MVC項(xiàng)目啟動(dòng)是從Global中的Application_Start()方法開始的,那就去看看它:
public class MvcApplication : System.Web.HttpApplication { protected void Application_Start() { RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); } } public class RouteConfig { public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); System.Web.Mvc.RouteCollectionExtensions routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } ); } }
看看我上面標(biāo)紅的代碼:這是路由注冊(cè),玄機(jī)就在這里。那我們?nèi)タ纯碝apRoute源碼就知道咯:
public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) { ...... Route route = new Route(url, new MvcRouteHandler()) { Defaults = new RouteValueDictionary(defaults), Constraints = new RouteValueDictionary(constraints), DataTokens = new RouteValueDictionary() }; ...... return route; }
看看我們5-8行代碼,在MVC應(yīng)用程序里,在路由注冊(cè)的時(shí)候,我們就已經(jīng)給他一個(gè)默認(rèn)的HttpRouteHandler對(duì)象,就是 New MvcRouteHandler().現(xiàn)在我們反推回去,我們MVC程序在路由注冊(cè)的時(shí)候就已經(jīng)確定了HttpRouteHandler為MvcRouteHandler,那么當(dāng)我們?cè)谇懊鍼ostResolveRequestCache方法里,當(dāng)我們的請(qǐng)求與路由匹配成功后,自然會(huì)返回的是MvcRouteHandler。
好啦,MvcRouteHandler生成了。那么MvcRouteHandler能做什么呢?又做了什么呢?
再回頭看看 PostResolveRequestCache方法,在成功獲取到IHttpRouteHandler對(duì)象即MvcRouteHandler之后,又做了下面這一個(gè)操作:
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
我們看看這個(gè)IHttpHandler 的源碼:
namespace System.Web.Routing { public interface IRouteHandler { IHttpHandler GetHttpHandler(RequestContext requestContext); } }
有一個(gè)GetHttpHandler的方法,恰好就調(diào)用了這個(gè)方法。那我們看看MvcRouteHandler是怎么實(shí)現(xiàn)這個(gè)GetHttpHandler的呢:
public class MvcRouteHandler : IRouteHandler { // Fields private IControllerFactory _controllerFactory; // Methods public MvcRouteHandler() { } public MvcRouteHandler(IControllerFactory controllerFactory) { this._controllerFactory = controllerFactory; } protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) { requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext)); return new MvcHandler(requestContext); } protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext) { string str = (string) requestContext.RouteData.Values["controller"]; if (string.IsNullOrWhiteSpace(str)) { throw new InvalidOperationException(MvcResources.MvcRouteHandler_RouteValuesHasNoController); } IControllerFactory factory = this._controllerFactory ?? ControllerBuilder.Current.GetControllerFactory(); return factory.GetControllerSessionBehavior(requestContext, str); } IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext) { return this.GetHttpHandler(requestContext); } }
看第16-20行代碼,這時(shí)候應(yīng)該明白了吧。順理成章的返回了MvcHandler對(duì)象。記得我們前面說過,請(qǐng)求最終是被相對(duì)應(yīng)的HttpHander對(duì)象處理的。MvcHandler就是那個(gè)用來處理Mvc請(qǐng)求的HttpHandler。MvcRouteHandler把請(qǐng)求交給了MvcHandler去做請(qǐng)求處理管道中后續(xù)事件的處理操作了。
下面我們就看看MvcHandler做了些什么:
MvcHandler
MvcHandler就是最終對(duì)request進(jìn)行處理。
MvcHandler的定義如下:
我們可以看到MvcHandler就是一個(gè)普通的Http Handler.我們知道一個(gè)http handler需要實(shí)現(xiàn)一個(gè)ProcessRequest()的方法,這個(gè)方法就是處理request的核心。所以MvcHandler實(shí)現(xiàn)了ProcessRequest()方法。
ProcessRequest主要功能:
(1)在ASP.NET MVC中,會(huì)調(diào)用MvcHandler的ProcessRequest()方法,此方法會(huì)激活具體請(qǐng)求的Controller類對(duì)象,觸發(fā)Action方法,返回ActionResult實(shí)例。
(2)如果ActionResult是非ViewResult,比如JsonResult, ContentResult,這些內(nèi)容將直接被輸送到Response響應(yīng)流中,顯示給客戶端;如果是ViewResult,就會(huì)進(jìn)入下一個(gè)渲染視圖環(huán)節(jié)。
(3)在渲染視圖環(huán)節(jié),ViewEngine找到需要被渲染的視圖,View被加載成WebViewPage<TModel>類型,并渲染生成Html,最終返回Html。
ProcessRequest()定義如下:
// Copyright (c) Microsoft Open Technologies, Inc.<pre>// All rights reserved. See License.txt in the project root for license information. void IHttpHandler.ProcessRequest(HttpContext httpContext) { ProcessRequest(httpContext); } protected virtual void ProcessRequest(HttpContext httpContext) { HttpContextBase iHttpContext = new HttpContextWrapper(httpContext); ProcessRequest(iHttpContext); } protected internal virtual void ProcessRequest(HttpContextBase httpContext) { SecurityUtil.ProcessInApplicationTrust(() => { IController controller; IControllerFactory factory; ProcessRequestInit(httpContext, out controller, out factory); try { controller.Execute(RequestContext); } finally { factory.ReleaseController(controller); } }); }
從上面的代碼可以看出調(diào)用了一個(gè)ProcessRequestInit()方法,定義如下:
private void ProcessRequestInit(HttpContextBase httpContext, out IController controller, out IControllerFactory factory) { // If request validation has already been enabled, make it lazy. // This allows attributes like [HttpPost] (which looks // at Request.Form) to work correctly without triggering full validation. bool? isRequestValidationEnabled = ValidationUtility.IsValidationEnabled(HttpContext.Current); if (isRequestValidationEnabled == true) { ValidationUtility.EnableDynamicValidation(HttpContext.Current); } AddVersionHeader(httpContext); RemoveOptionalRoutingParameters(); // Get the controller type string controllerName = RequestContext.RouteData.GetRequiredString("controller"); // Instantiate the controller and call Execute factory = ControllerBuilder.GetControllerFactory(); controller = factory.CreateController(RequestContext, controllerName); if (controller == null) { throw new InvalidOperationException( String.Format( CultureInfo.CurrentCulture, MvcResources.ControllerBuilder_FactoryReturnedNull, factory.GetType(), controllerName)); } }
在ProcessRequestInit()方法中首先創(chuàng)建了ControllerFactory()的對(duì)象 factory.然后ControllerFactory創(chuàng)建了相關(guān)Controller的實(shí)例.最終調(diào)用了Controller的Excute()方法。
好我們?cè)賮砜纯碈ontrollerFactory:
ControllerFactory
主要是用來生成Controller對(duì)象
ControllerFactory實(shí)現(xiàn)了接口IControllerFactory.
Controller
到這里我們大概就知道了,MvcHandler通過ProcessRequest()方法最終創(chuàng)建了Controller對(duì)象,這里我們都應(yīng)該知道,Controller里面包含很多的Action方法,每一次請(qǐng)求至少一個(gè)Action方法會(huì)被調(diào)用。為了明確的實(shí)現(xiàn)IController接口,框架里面有一個(gè)ControllerBase的類已經(jīng)實(shí)現(xiàn)了IController接口,其實(shí)我們自己的Controller也可以不繼承ControllerBase,只要實(shí)現(xiàn)IController接口即可。
public abstract class ControllerBase : IController { protected virtual void Execute(RequestContext requestContext) { if (requestContext == null) { throw new ArgumentNullException("requestContext"); } if (requestContext.HttpContext == null) { throw new ArgumentException( MvcResources.ControllerBase_CannotExecuteWithNullHttpContext, "requestContext"); } VerifyExecuteCalledOnce(); Initialize(requestContext); using (ScopeStorage.CreateTransientScope()) { ExecuteCore(); } } protected abstract void ExecuteCore(); // .......
controller對(duì)象實(shí)際上使用ActionInvoker來調(diào)用Action方法的,當(dāng)Controller對(duì)象被創(chuàng)建后,會(huì)執(zhí)行Controller對(duì)象的基類ControllerBase類里面的Excute方法。Excute方法又調(diào)用了ExcuteCore()方法。Controller類里面實(shí)現(xiàn)了ExcuteCore()方法。ExcuteCore調(diào)用了ActionInvoker的InvokerAction方法來調(diào)用Action方法。
ActionInvoker
ActionInvoker方法有很重要的責(zé)任來查找Controller中的Action方法并且調(diào)用。
ActionInvoker是一個(gè)實(shí)現(xiàn)了IActionInvoker接口的對(duì)象:
bool InvokeAction( ControllerContext controllerContext, string actionName )
Controller類里面暴露了一個(gè)ActionInvoker 屬性,會(huì)返回一個(gè)ControllerActionInvoker 。ActionInvoker通過CreateActionInvoker()方法來創(chuàng)建ControllerActionInvoker對(duì)象。
public IActionInvoker ActionInvoker { get { if (_actionInvoker == null) { _actionInvoker = CreateActionInvoker(); } return _actionInvoker; } set { _actionInvoker = value; } } protected virtual IActionInvoker CreateActionInvoker() { return new ControllerActionInvoker(); }
我們看到CreateActionInvoker()是一個(gè)Virtual方法,我們可以實(shí)現(xiàn)自己的ActionInvoker.
ActionInvoker類需要匹配Controller中詳細(xì)的Action來執(zhí)行,而這些詳細(xì)的信息是由ControllerDescriptor 提供的。ControllerDescriptor 和ActionDescriptor在ActionInvoker中扮演重要的角色。這兩個(gè)分別是對(duì)Controler和Action的詳細(xì)描述。ControllerDescriptor 描述了Controller的相關(guān)信息比如name,action,type等。
ActionDescriptor 描述了Action相關(guān)的詳情,比如name,controller,parameters,attributes和fiflters等。
ActionDescriptor 中一個(gè)中要的方法就是FindAction(),這個(gè)方法返回一個(gè)ActionDescriptor 對(duì)象,所以ActionInvoker知道該調(diào)用哪個(gè)Action。
ActionResult
到目前為止,我們看到了Action方法被ActionInvoker調(diào)用。所有的Action方法有一個(gè)特性,就是返回一個(gè)ActionResult類型的數(shù)據(jù)。
public abstract class ActionResult { public abstract void ExecuteResult(ControllerContext context); }
ExecuteResult()是一個(gè)抽象方法,所以不同的子類可以提供不同的ExecuteResult()實(shí)現(xiàn)。
ActionResult執(zhí)行后響應(yīng)輸出到客戶端。
ViewEngine
ViewResult幾乎是大部分應(yīng)用程序的返回類型,主要通過ViewEngine引擎來展示view的。ViewEngine可能主要就是生成Html元素的引擎。Framwork提供了2種引擎,Razor View Engine 和Web Form View Engine.如果你想自定義引擎,你可以創(chuàng)建一個(gè)引擎只要實(shí)現(xiàn)IViewEngine接口即可。
IViewEngine 有下面幾個(gè)方法:
1、FindPartialView :當(dāng)controller需要返回一個(gè)PartialView的時(shí)候,F(xiàn)indPartialView方法 就會(huì)被調(diào)用。
2、FindView
3、ReleaseView :主要用來有ViewEngine釋放資源
ViewResultBase 和ViewResult是比較重要的兩個(gè)類。ViewResultBase 包含下面的實(shí)現(xiàn)代碼:
if (View == null) { result = FindView(context); //calls the ViewResult's FindView() method View = result.View; } ViewContext viewContext = new ViewContext(context, View, ViewData, TempData); View.Render(viewContext, context.HttpContext.Response.Output); protected abstract ViewEngineResult FindView(ControllerContext context); //this is implemented by //the ViewResult
protected override ViewEngineResult FindView(ControllerContext context) { ViewEngineResult result = ViewEngineCollection.FindView(context, ViewName, MasterName); if (result.View != null) { return result; } //rest of the code omitted }
當(dāng)ViewResult的方法ExecuteResult被調(diào)用后,ViewResultBase 的ExecuteResult 方法被調(diào)用,然后ViewResultBase 調(diào)用ViewResult的FindView 。緊接著ViewResult 返回ViewEngineResult,之后ViewEngineResult調(diào)用Render()方法來繪制html輸出響應(yīng)。
關(guān)于“asp.net MVC應(yīng)用程序生命周期的示例分析”這篇文章就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,使各位可以學(xué)到更多知識(shí),如果覺得文章不錯(cuò),請(qǐng)把它分享出去讓更多的人看到。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。