溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

asp.net MVC應(yīng)用程序生命周期的示例分析

發(fā)布時(shí)間:2021-08-12 11:36:36 來源:億速云 閱讀:132 作者:小新 欄目:開發(fā)技術(shù)

這篇文章將為大家詳細(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)歷的管道事件:

asp.net MVC應(yīng)用程序生命周期的示例分析

上圖就是一個(gè)完整的mvc應(yīng)用程序的一個(gè)http請(qǐng)求到響應(yīng)的整個(gè)兒所經(jīng)歷的流程。從UrlRoutingModule攔截請(qǐng)求到最終ActionResult執(zhí)行ExecuteResult方法生成響應(yīng)。

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

UrlRoutingModule

asp.net MVC應(yīng)用程序生命周期的示例分析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):

asp.net MVC應(yīng)用程序生命周期的示例分析

從上圖中我們看到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屬性。

asp.net MVC應(yīng)用程序生命周期的示例分析

那么UrlRouting Module是如何選擇匹配規(guī)則的呢?

asp.net MVC應(yīng)用程序生命周期的示例分析

我們看看我們新建的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

asp.net MVC應(yīng)用程序生命周期的示例分析生成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

asp.net MVC應(yīng)用程序生命周期的示例分析MvcHandler就是最終對(duì)request進(jìn)行處理。

MvcHandler的定義如下:

asp.net MVC應(yīng)用程序生命周期的示例分析

我們可以看到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

asp.net MVC應(yīng)用程序生命周期的示例分析主要是用來生成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)用。

asp.net MVC應(yīng)用程序生命周期的示例分析

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接口即可。

asp.net MVC應(yīng)用程序生命周期的示例分析

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)把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(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)容。

AI