欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于asp.net MVC 應(yīng)用程序的生命周期(詳解)

 更新時(shí)間:2017年12月14日 14:24:19   作者:殘風(fēng)飛雪  
下面小編就為大家分享一篇基于asp.net MVC 應(yīng)用程序的生命周期詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧

首先我們知道http是一種無(wú)狀態(tài)的請(qǐng)求,他的生命周期就是從客戶端瀏覽器發(fā)出請(qǐng)求開(kāi)始,到得到響應(yīng)結(jié)束。那么MVC應(yīng)用程序從發(fā)出請(qǐng)求到獲得響應(yīng),都做了些什么呢?

本文我們會(huì)詳細(xì)討論MVC應(yīng)用程序一個(gè)請(qǐng)求的生命周期,從一個(gè)控件到另一個(gè)控件是怎樣被處理的。我們還會(huì)詳細(xì)介紹一下整個(gè)請(qǐng)求的生命周期中,用到的相關(guān)組件。因?yàn)樵谄匠5拈_(kāi)發(fā)過(guò)程中,我們可能知道怎樣去使用MVC框架來(lái)處理相關(guān)的請(qǐng)求,大部分的時(shí)候我們只是在controller和action方法之間做相關(guān)的處理,對(duì)于真正內(nèi)在的運(yùn)行機(jī)制可能不是很了解。其實(shí)當(dāng)我們對(duì)內(nèi)在機(jī)制有了一定的了解以后,會(huì)發(fā)現(xiàn)微軟的MVC框架的擴(kuò)展性很強(qiáng),到處都留有擴(kuò)展接口,讓我們通過(guò)擴(kuò)展能夠自己定義自己所需要的處理機(jī)制,這也正是為什么MVC框架如此出名的原因。

當(dāng)我最開(kāi)始學(xué)習(xí)使用mvc的時(shí)候,困擾我的一個(gè)問(wèn)題就是,一個(gè)請(qǐng)求的流程控制是怎樣的呢?從view到controller再到action之間經(jīng)歷了什么?那個(gè)時(shí)候我還不清楚HTTP module和HTTP handler在處理一個(gè)請(qǐng)求中扮演什么樣的角色,起什么樣的作用呢。畢竟MVC是一個(gè)web開(kāi)發(fā)框架,在整個(gè)請(qǐng)求處理過(guò)程中,肯定包含了http module和http handler。其實(shí)還有很多相關(guān)的組件包含在一個(gè)完整的mvc應(yīng)用程序請(qǐng)求生命周期里,在整個(gè)請(qǐng)求過(guò)程中他們都扮演者非常重要的角色。盡管大部分時(shí)候我們都使用的是框架提供的默認(rèn)的函數(shù),但是如果我們了解了每個(gè)控件所扮演的角色,我們就可以輕松的擴(kuò)展和使用我們自己實(shí)現(xiàn)的方法,就目前來(lái)說(shuō)MVC是擴(kuò)展性比較強(qiáng)的框架。

下面是本章節(jié)的主要內(nèi)容:

HttpApplication

HttpModule

HttpHandler

ASP.NET MVC運(yùn)行機(jī)制

UrlRoutingModule

RouteHandler

MvcHandler

ControllerFactory

Controller

ActionInvoker

ActionResult

ViewEngine

HttpApplication

我們都知道,在ASP.NET MVC框架出現(xiàn)之前,我們大部分開(kāi)發(fā)所使用的框架都是ASP.NET WebForm.其實(shí)不管是MVC還是WebForm,在請(qǐng)求處理機(jī)制上,大部分是相同的。這涉及到IIS對(duì)請(qǐng)求的處理,涉及的知識(shí)較多,我們就不做介紹了,下次有機(jī)會(huì)我寫一篇專文。我們從HttpApplication說(shuō)起。先看看微軟官方是怎么定義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í)例來(lái)處理其生存期中收到的眾多請(qǐng)求。但是,它每次只能處理一個(gè)請(qǐng)求。這樣,成員變量才可用于存儲(chǔ)針對(duì)每個(gè)請(qǐng)求的數(shù)據(jù)。

意思就是說(shuō)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ù)雜的過(guò)程,在整個(gè)過(guò)程中,不同階段會(huì)觸發(fā)相映的事件。我們可以注冊(cè)相應(yīng)的事件,將處理邏輯注入到HttpApplication處理請(qǐng)求的某個(gè)階段。在HttpApplication這個(gè)類中定義了19個(gè)事件來(lái)處理到達(dá)HttpApplication實(shí)例的請(qǐng)求。就是說(shuō)不管MVC還是WebForm,最終都要經(jīng)過(guò)這19個(gè)事件的處理,那么除了剛才說(shuō)的MVC和WebFrom在請(qǐng)求處理機(jī)制上大部分都是相同的,不同之處在哪呢?他們是從哪里開(kāi)始分道揚(yáng)鑣的呢?我們猜想肯定就在這19個(gè)方法中。我們繼續(xù)往下看。

我們來(lái)看看這19個(gè)事件:

應(yīng)用程序按照以下順序執(zhí)行由 global.asax 文件中定義的模塊或用戶代碼處理的事件:

事件名稱:

簡(jiǎn)單描述:

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 事件的功能可以訪問(wèn)由 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ā)生,從而跳過(guò)事件處理程序(例如某個(gè)頁(yè)或 XML Web services)的執(zhí)行

PostResolveRequestCache

ASP.NET 跳過(guò)當(dāng)前事件處理程序的執(zhí)行并允許緩存模塊滿足來(lái)自緩存的請(qǐng)求時(shí)發(fā)生。)在 PostResolveRequestCache 事件之后、PostMapRequestHandler 事件之前創(chuàng)建一個(gè)事件處理程序(對(duì)應(yīng)于請(qǐng)求 URL 的頁(yè)

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 開(kāi)始執(zhí)行事件處理程序(例如,某頁(yè)或某個(gè) XML Web services)前發(fā)生。

PostRequestHandlerExecute

ASP.NET 事件處理程序(例如,某頁(yè)或某個(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)用程序來(lái)說(shuō),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來(lái)處理。所有的HttpHandler都實(shí)現(xiàn)了IhttpHandler接口。

public interface IHttpHandler
{
 // Methods
 void ProcessRequest(HttpContext context);

 // Properties
 bool IsReusable { get; }
}

我們看到該接口有一個(gè)方法ProcessRequest,顧名思義這個(gè)方法就是主要用來(lái)處理請(qǐng)求的。所以說(shuō)每一個(gè)請(qǐng)求最終分發(fā)到自己相應(yīng)的HttpHandler來(lái)處理該請(qǐng)求。

ASP.NET MVC 運(yùn)行機(jī)制

好了,上面說(shuō)了那么多,其實(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)。

下面我們就來(lái)詳細(xì)講解一下這些過(guò)程都做了些什么。

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è)疑問(wèn)我們繼續(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è)全局配置,就是說(shuō)所有的ASP.NET請(qǐng)求都會(huì)到達(dá)這里,所以該Module還不能最終決定是MVC還是WebForm請(qǐng)求。但是也是至關(guān)重要的地方。

(2)通過(guò)在全局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事件。也就是說(shuō)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的源碼來(lái)看看,以下是幾句核心的代碼:

我們?cè)俜治鲆幌逻@個(gè)方法的源碼:

public virtual void PostResolveRequestCache(HttpContextBase context)
{
 // 通過(guò)RouteCollection的靜態(tài)方法GetRouteData獲取到封裝路由信息的RouteData實(shí)例
 RouteData routeData = this.RouteCollection.GetRouteData(context);
 if (routeData != null)
 {
 // 再?gòu)腞outeData中獲取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ī)則,返回的不為空,說(shuō)明匹配正確,關(guān)于路由規(guī)則的匹配,說(shuō)起來(lái)也不短,這里就不大幅介紹,有時(shí)間下次再開(kāi)篇詳解路由機(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)求,沒(méi)有匹配到任何路由,那么該請(qǐng)求就不會(huì)被處理。

這里返回的RouteData里的RouteHandler就是MVCRouteHandler。為什么呢?那我們繼續(xù)往下看RouteHandler。

RouteHandler

生成MvcHander

在上面路由匹配的過(guò)程中,與匹配路由相關(guān)聯(lián)的MvcRouteHandler ,MvcRouteHandler 實(shí)現(xiàn)了IRouteHandler 接口。MvcRouteHandler 主要是用來(lái)獲取對(duì)MvcHandler的引用。MvcHandler實(shí)現(xiàn)了IhttpHandler接口。

MVCRouteHandler的作用是用來(lái)生成實(shí)現(xiàn)IHttpHandler接口的MvcHandler。而我們前面說(shuō)過(guò)最終處理請(qǐng)求的都是相對(duì)應(yīng)的HttpHandler。那么處理MVC請(qǐng)求的自然就是這個(gè)MvcHandler。所以這里返回MvcRouteHandler至關(guān)重要:

那么,MvcRouteHandler從何而來(lái)呢?眾所周知,ASP.NET MVC項(xiàng)目啟動(dòng)是從Global中的Application_Start()方法開(kāi)始的,那就去看看它:

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ì)象。記得我們前面說(shuō)過(guò),請(qǐng)求最終是被相對(duì)應(yīng)的HttpHander對(duì)象處理的。MvcHandler就是那個(gè)用來(lái)處理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è)賮?lái)看看ControllerFactory:

ControllerFactory

主要是用來(lái)生成Controller對(duì)象

ControllerFactory實(shí)現(xiàn)了接口IControllerFactory.

Controller

這里我們大概就知道了,MvcHandler通過(guò)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來(lái)調(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方法來(lái)調(diào)用Action方法。

ActionInvoker

ActionInvoker方法有很重要的責(zé)任來(lái)查找Controller中的Action方法并且調(diào)用。

ActionInvoker是一個(gè)實(shí)現(xiàn)了IActionInvoker接口的對(duì)象:

bool InvokeAction(
  ControllerContext controllerContext,
  string actionName
) 

Controller類里面暴露了一個(gè)ActionInvoker 屬性,會(huì)返回一個(gè)ControllerActionInvoker 。ActionInvoker通過(guò)CreateActionInvoker()方法來(lái)創(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來(lái)執(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)用程序的返回類型,主要通過(guò)ViewEngine引擎來(lái)展示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 :主要用來(lái)有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()方法來(lái)繪制html輸出響應(yīng)。

總結(jié):如果我們理解了整個(gè)過(guò)程中發(fā)生了什么,哪些類和哪些方法被調(diào)用,我們就可以在需要擴(kuò)展的地方輕松的進(jìn)行擴(kuò)展。

以上這篇基于asp.net MVC 應(yīng)用程序的生命周期(詳解)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

您可能感興趣的文章:

相關(guān)文章

最新評(píng)論