asp.netMVC應(yīng)用程序生命周期的示例分析-創(chuàng)新互聯(lián)

這篇文章將為大家詳細講解有關(guān)asp.net MVC應(yīng)用程序生命周期的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

創(chuàng)新互聯(lián)于2013年創(chuàng)立,先為南丹等服務(wù)建站,南丹等地企業(yè),進行企業(yè)商務(wù)咨詢服務(wù)。為南丹企業(yè)網(wǎng)站制作PC+手機+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

我們都知道,在ASP.NET MVC框架出現(xiàn)之前,我們大部分開發(fā)所使用的框架都是ASP.NET WebForm.其實不管是MVC還是WebForm,在請求處理機制上,大部分是相同的。這涉及到IIS對請求的處理,涉及的知識較多,我們就不做介紹了,下次有機會我寫一篇專文。我們從HttpApplication說起。先看看微軟官方是怎么定義HttpApplication的:

定義 ASP.NET 應(yīng)用程序中的所有應(yīng)用程序?qū)ο蠊灿械姆椒?、屬性和事件。此類是用戶?Global.asax 文件中所定義的應(yīng)用程序的基類。

可能我翻譯不是很準確,原文連接在這里:https://msdn.microsoft.com/en-us/library/system.web.httpapplication(v=vs.110).aspx

微軟官方文檔中Remark里有這么一段話:HttpApplication 類的實例是在 ASP.NET 基礎(chǔ)結(jié)構(gòu)中創(chuàng)建的,而不是由用戶直接創(chuàng)建的。使用 HttpApplication 類的一個實例來處理其生存期中收到的眾多請求。但是,它每次只能處理一個請求。這樣,成員變量才可用于存儲針對每個請求的數(shù)據(jù)。

意思就是說ASP.NET應(yīng)用程序,不管是MVC還是WebForm,最終都會到達一個HttpApplication類的實例。HttpApplication是整個ASP.NET基礎(chǔ)架構(gòu)的核心,負責(zé)處理分發(fā)給他的請求。HttpApplication處理請求的周期是一個復(fù)雜的過程,在整個過程中,不同階段會觸發(fā)相映的事件。我們可以注冊相應(yīng)的事件,將處理邏輯注入到HttpApplication處理請求的某個階段。在HttpApplication這個類中定義了19個事件來處理到達HttpApplication實例的請求。就是說不管MVC還是WebForm,最終都要經(jīng)過這19個事件的處理,那么除了剛才說的MVC和WebFrom在請求處理機制上大部分都是相同的,不同之處在哪呢?他們是從哪里開始分道揚鑣的呢?我們猜想肯定就在這19個方法中。我們繼續(xù)往下看。

我們來看看這19個事件:

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

事件名稱:

簡單描述:

BeginRequest

在 ASP.NET 響應(yīng)請求時作為 HTTP 執(zhí)行管線鏈中的第一個事件發(fā)生

AuthenticateRequest

當安全模塊已建立用戶標識時發(fā)生。注:AuthenticateRequest 事件發(fā)出信號表示配置的身份驗證機制已對當前請求進行了身份驗證。預(yù)訂 AuthenticateRequest 事件可確保在處理附加的模塊或事件處理程序之前對請求進行身份驗證

PostAuthenticateRequest

當安全模塊已建立用戶標識時發(fā)生。PostAuthenticateRequest 事件在 AuthenticateRequest 事件發(fā)生之后引發(fā)。預(yù)訂 PostAuthenticateRequest 事件的功能可以訪問由 PostAuthenticateRequest 處理的任何數(shù)據(jù)

AuthorizeRequest

當安全模塊已驗證用戶授權(quán)時發(fā)生。AuthorizeRequest 事件發(fā)出信號表示 ASP.NET 已對當前請求進行了授權(quán)。預(yù)訂 AuthorizeRequest 事件可確保在處理附加的模塊或事件處理程序之前對請求進行身份驗證和授權(quán)

PostAuthorizeRequest

在當前請求的用戶已獲授權(quán)時發(fā)生。PostAuthorizeRequest 事件發(fā)出信號表示 ASP.NET 已對當前請求進行了授權(quán)。預(yù)訂PostAuthorizeRequest 事件可確保在處理附加的模塊或處理程序之前對請求進行身份驗證和授權(quán)

ResolveRequestCache

當 ASP.NET 完成授權(quán)事件以使緩存模塊從緩存中為請求提供服務(wù)時發(fā)生,從而跳過事件處理程序(例如某個頁或 XML Web services)的執(zhí)行

PostResolveRequestCache

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

PostMapRequestHandler

在 ASP.NET 已將當前請求映射到相應(yīng)的事件處理程序時發(fā)生。

AcquireRequestState

當 ASP.NET 獲取與當前請求關(guān)聯(lián)的當前狀態(tài)(如會話狀態(tài))時發(fā)生。

PostAcquireRequestState

在已獲得與當前請求關(guān)聯(lián)的請求狀態(tài)(例如會話狀態(tài))時發(fā)生。

PreRequestHandlerExecute

恰好在 ASP.NET 開始執(zhí)行事件處理程序(例如,某頁或某個 XML Web services)前發(fā)生。

PostRequestHandlerExecute

在 ASP.NET 事件處理程序(例如,某頁或某個 XML Web service)執(zhí)行完畢時發(fā)生。

ReleaseRequestState

在 ASP.NET 執(zhí)行完所有請求事件處理程序后發(fā)生。該事件將使狀態(tài)模塊保存當前狀態(tài)數(shù)據(jù)。

PostReleaseRequestState

在 ASP.NET 已完成所有請求事件處理程序的執(zhí)行并且請求狀態(tài)數(shù)據(jù)已存儲時發(fā)生。

UpdateRequestCache

當 ASP.NET 執(zhí)行完事件處理程序以使緩存模塊存儲將用于從緩存為后續(xù)請求提供服務(wù)的響應(yīng)時發(fā)生。

PostUpdateRequestCache

在 ASP.NET 完成緩存模塊的更新并存儲了用于從緩存中為后續(xù)請求提供服務(wù)的響應(yīng)后,發(fā)生此事件。

LogRequest

在 ASP.NET 完成緩存模塊的更新并存儲了用于從緩存中為后續(xù)請求提供服務(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)請求時作為 HTTP 執(zhí)行管線鏈中的最后一個事件發(fā)生。

在調(diào)用 CompleteRequest 方法時始終引發(fā) EndRequest 事件。

對于一個ASP.NET應(yīng)用程序來說,HttpApplication派生與Global.aspx(可以看看我們創(chuàng)建的應(yīng)用程序都有一個Global.aspx文件),我們可以在Global.aspx文件中對HttpApplication的請求進行定制即注入這19個事件中的某個事件進行邏輯處理操作。在Global.aspx中我們按照"Application_{Event Name}"這樣的方法命名進行事件注冊。

Event Name就是上面19個事件的名稱。比如Application_EndRequest就用于處理Application的EndRequest事件。

HttpModule

ASP.NET擁有一個高度可擴展的引擎,并且能夠處理對于不同資源類型的請求。這就是HttpModule。當一個請求轉(zhuǎn)入ASP.net管道時,最終負責(zé)處理請求的是與資源相匹配的HttpHandler對象,但是在HttpHandler進行處理之前,ASP.NET先會加載并初始化所有配置的HttpModule對象。HttpModule初始化的時候,會將一些回調(diào)事件注入到HttpApplication相應(yīng)的事件中。所有的HttpModule都實現(xiàn)了IHttpModule接口,該接口有一個有一個Init方法。

public interface IHttpModule
{
 // Methods
 void Dispose();
 void Init(HttpApplication context);
}

看到Init方法呢接受一個HttpApplication對象,有了這個對象就很容易注冊HttpApplication中19個事件中的某個事件了。這樣當HttpApplication對象執(zhí)行到某個事件的時候自然就會出發(fā)。

HttpHandler

對于不同的資源類型的請求,ASP.NET會加載不同的HttpHandler來處理。所有的HttpHandler都實現(xiàn)了IhttpHandler接口。

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

 // Properties
 bool IsReusable { get; }
}

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

ASP.NET MVC 運行機制

好了,上面說了那么多,其實都是給這里做鋪墊呢。終于到正題了。先看看下面這張圖,描述了MVC的主要經(jīng)歷的管道事件:

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

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

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

UrlRoutingModule

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

首先發(fā)起一個請求,我們前面講到ASP.NET 會加載一個HttpModule對象的初始化事件Init,而所有的HttpModule對象都實現(xiàn)了IHttpModule接口。我們看看UrlRoutingModule的實現(xiàn):

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

從上圖中我們看到UrlRoutingModule實現(xiàn)了接口IHttpModule,當一個請求轉(zhuǎn)入ASP.NET管道時,就會加載 UrlRoutingModule對象的Init()方法。

那么為什么偏偏是UrlRoutingModule被加載初始化了呢?為什么不是別的HttpModule對象呢?帶著這個疑問我們繼續(xù)。

在ASP.NET MVC中,最核心的當屬“路由系統(tǒng)”,而路由系統(tǒng)的核心則源于一個強大的System.Web.Routing.dll組件。System.Web.Routing.dll不是MVC所特有的,但是MVC框架和它是密不可分的。

首先,我們要了解一下UrlRoutingModule是如何起作用的。

(1)IIS網(wǎng)站的配置可以分為兩個塊:全局 Web.config 和本站 Web.config。Asp.Net Routing屬于全局性的,所以它配置在全局Web.Config 中,我們可以在如下路徑中找到:“C\Windows\Microsoft.NET\Framework\版本號\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)]有,我上面標紅的那一行:<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />

UrlRoutingModule并不是MVC特有的,這是一個全局配置,就是說所有的ASP.NET請求都會到達這里,所以該Module還不能最終決定是MVC還是WebForm請求。但是也是至關(guān)重要的地方。

(2)通過在全局Web.Config中注冊 System.Web.Routing.UrlRoutingModule,IIS請求處理管道接到請求后,就會加載 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源碼里面是怎么實現(xiàn)Init方法的,Init()方法里面我標注紅色的地方:

application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);

這一步至關(guān)重要哈,看到?jīng)]有,就是對我們在HttpApplication那19個事件中的PostResolveRequestCache事件的注冊。注冊的方法是OnApplicationPostResolveRequestCache事件。也就是說HttpApplication對象在執(zhí)行到PostResolveRequestCache這個事件的時候,就會執(zhí)行OnApplicationPostResolveRequestCache事件。決定是MVC機制處理請求的關(guān)鍵所在就是OnApplicationPostResolveRequestCache事件。

從源碼中我們看出,OnApplicationPostResolveRequestCache事件執(zhí)行的時候,最終執(zhí)行了PostResolveRequestCache這個方法。最關(guān)鍵的地方呢就在這里了。

當請求到達UrlRoutingModule的時候,UrlRoutingModule取出請求中的Controller、Action等RouteData信息,與路由表中的所有規(guī)則進行匹配,若匹配,把請求交給IRouteHandler,即MVCRouteHandler。我們可以看下UrlRoutingModule的源碼來看看,以下是幾句核心的代碼:

我們再分析一下這個方法的源碼:

public virtual void PostResolveRequestCache(HttpContextBase context)
{
 // 通過RouteCollection的靜態(tài)方法GetRouteData獲取到封裝路由信息的RouteData實例
 RouteData routeData = this.RouteCollection.GetRouteData(context);
 if (routeData != null)
 {
 // 再從RouteData中獲取MVCRouteHandler
 IRouteHandler routeHandler = routeData.RouteHandler;
 ......
 if (!(routeHandler is StopRoutingHandler))
 {
 ......
 // 調(diào)用 IRouteHandler.GetHttpHandler(),獲取的IHttpHandler 類型實例,它是由 IRouteHandler.GetHttpHandler獲取的,這個得去MVC的源碼里看
 IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
 ......
 // 合適條件下,把之前將獲取的IHttpHandler 類型實例 映射到IIS HTTP處理管道中
 context.RemapHandler(httpHandler);
 }
 }
}

看到了吧,通過路由規(guī)則,返回的不為空,說明匹配正確,關(guān)于路由規(guī)則的匹配,說起來也不短,這里就不大幅介紹,有時間下次再開篇詳解路由機制。匹配成功后,返回一個RouteData類型的對象,RouteData對象都有些什么屬性呢?看看這行源碼: IRouteHandler routeHandler = routeData.RouteHandler;或者看源碼我們知道,RouteDate有一個RouteHandler屬性。

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

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

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

我們看看我們新建的MVC應(yīng)用程序,在App_Start文件夾下面有一個RouteConfig.cs類,這個類的內(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 }
 );
 }
 }
}

我們在這個類里面,主要是給路由表添加路由規(guī)則。在看看上面的UrlRoutingModule類,里面有一個RoutCollection屬性,所以UrlRoutingModule能夠獲取路由表中的所有規(guī)則,這里值得注意的是,路由規(guī)則的匹配是有順序的,如果有多個規(guī)則都能夠匹配,UrlRoutingModule至選擇第一個匹配的規(guī)則就返回,不再繼續(xù)往下匹配了。相反的如果一個請求,沒有匹配到任何路由,那么該請求就不會被處理。

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

RouteHandler

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

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

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

那么,MvcRouteHandler從何而來呢?眾所周知,ASP.NET MVC項目啟動是從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 }
 );
 }
 }

看看我上面標紅的代碼:這是路由注冊,玄機就在這里。那我們?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)用程序里,在路由注冊的時候,我們就已經(jīng)給他一個默認的HttpRouteHandler對象,就是 New MvcRouteHandler().現(xiàn)在我們反推回去,我們MVC程序在路由注冊的時候就已經(jīng)確定了HttpRouteHandler為MvcRouteHandler,那么當我們在前面PostResolveRequestCache方法里,當我們的請求與路由匹配成功后,自然會返回的是MvcRouteHandler。

好啦,MvcRouteHandler生成了。那么MvcRouteHandler能做什么呢?又做了什么呢?

再回頭看看 PostResolveRequestCache方法,在成功獲取到IHttpRouteHandler對象即MvcRouteHandler之后,又做了下面這一個操作:

IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);

我們看看這個IHttpHandler 的源碼:

namespace System.Web.Routing
{ 
 public interface IRouteHandler
 { 
 IHttpHandler GetHttpHandler(RequestContext requestContext);
 }
}

有一個GetHttpHandler的方法,恰好就調(diào)用了這個方法。那我們看看MvcRouteHandler是怎么實現(xiàn)這個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行代碼,這時候應(yīng)該明白了吧。順理成章的返回了MvcHandler對象。記得我們前面說過,請求最終是被相對應(yīng)的HttpHander對象處理的。MvcHandler就是那個用來處理Mvc請求的HttpHandler。MvcRouteHandler把請求交給了MvcHandler去做請求處理管道中后續(xù)事件的處理操作了。

下面我們就看看MvcHandler做了些什么:

MvcHandler

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

MvcHandler的定義如下:

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

我們可以看到MvcHandler就是一個普通的Http Handler.我們知道一個http handler需要實現(xiàn)一個ProcessRequest()的方法,這個方法就是處理request的核心。所以MvcHandler實現(xiàn)了ProcessRequest()方法。

ProcessRequest主要功能:

(1)在ASP.NET MVC中,會調(diào)用MvcHandler的ProcessRequest()方法,此方法會激活具體請求的Controller類對象,觸發(fā)Action方法,返回ActionResult實例。

(2)如果ActionResult是非ViewResult,比如JsonResult, ContentResult,這些內(nèi)容將直接被輸送到Response響應(yīng)流中,顯示給客戶端;如果是ViewResult,就會進入下一個渲染視圖環(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)用了一個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()的對象 factory.然后ControllerFactory創(chuàng)建了相關(guān)Controller的實例.最終調(diào)用了Controller的Excute()方法。

好我們再來看看ControllerFactory:

ControllerFactory

asp.net MVC應(yīng)用程序生命周期的示例分析主要是用來生成Controller對象

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

Controller

到這里我們大概就知道了,MvcHandler通過ProcessRequest()方法最終創(chuàng)建了Controller對象,這里我們都應(yīng)該知道,Controller里面包含很多的Action方法,每一次請求至少一個Action方法會被調(diào)用。為了明確的實現(xiàn)IController接口,框架里面有一個ControllerBase的類已經(jīng)實現(xiàn)了IController接口,其實我們自己的Controller也可以不繼承ControllerBase,只要實現(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對象實際上使用ActionInvoker來調(diào)用Action方法的,當Controller對象被創(chuàng)建后,會執(zhí)行Controller對象的基類ControllerBase類里面的Excute方法。Excute方法又調(diào)用了ExcuteCore()方法。Controller類里面實現(xiàn)了ExcuteCore()方法。ExcuteCore調(diào)用了ActionInvoker的InvokerAction方法來調(diào)用Action方法。

ActionInvoker

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

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

ActionInvoker是一個實現(xiàn)了IActionInvoker接口的對象:

bool InvokeAction(
  ControllerContext controllerContext,
  string actionName
)

Controller類里面暴露了一個ActionInvoker 屬性,會返回一個ControllerActionInvoker 。ActionInvoker通過CreateActionInvoker()方法來創(chuàng)建ControllerActionInvoker對象。

public IActionInvoker ActionInvoker {
 get {
 if (_actionInvoker == null) {
  _actionInvoker = CreateActionInvoker();
 }
 return _actionInvoker;
 }
 set {
 _actionInvoker = value;
 }
}
 protected virtual IActionInvoker CreateActionInvoker() {
 return new ControllerActionInvoker();
}

我們看到CreateActionInvoker()是一個Virtual方法,我們可以實現(xiàn)自己的ActionInvoker.

ActionInvoker類需要匹配Controller中詳細的Action來執(zhí)行,而這些詳細的信息是由ControllerDescriptor 提供的。ControllerDescriptor 和ActionDescriptor在ActionInvoker中扮演重要的角色。這兩個分別是對Controler和Action的詳細描述。ControllerDescriptor 描述了Controller的相關(guān)信息比如name,action,type等。

ActionDescriptor 描述了Action相關(guān)的詳情,比如name,controller,parameters,attributes和fiflters等。

ActionDescriptor 中一個中要的方法就是FindAction(),這個方法返回一個ActionDescriptor 對象,所以ActionInvoker知道該調(diào)用哪個Action。

ActionResult

到目前為止,我們看到了Action方法被ActionInvoker調(diào)用。所有的Action方法有一個特性,就是返回一個ActionResult類型的數(shù)據(jù)。

public abstract class ActionResult
 {
 public abstract void ExecuteResult(ControllerContext context);
 }

ExecuteResult()是一個抽象方法,所以不同的子類可以提供不同的ExecuteResult()實現(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)建一個引擎只要實現(xiàn)IViewEngine接口即可。

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

IViewEngine 有下面幾個方法:

1、FindPartialView :當controller需要返回一個PartialView的時候,F(xiàn)indPartialView方法 就會被調(diào)用。

2、FindView

3、ReleaseView :主要用來有ViewEngine釋放資源

ViewResultBase 和ViewResult是比較重要的兩個類。ViewResultBase 包含下面的實現(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 
 }

當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)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

當前題目:asp.netMVC應(yīng)用程序生命周期的示例分析-創(chuàng)新互聯(lián)
本文網(wǎng)址:http://muchs.cn/article34/higse.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設(shè)、ChatGPT、網(wǎng)站營銷全網(wǎng)營銷推廣、App設(shè)計App開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都seo排名網(wǎng)站優(yōu)化