這篇文章將為大家詳細講解有關asp.net MVC應用程序生命周期的示例分析,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
我們都知道,在ASP.NET MVC框架出現之前,我們大部分開發所使用的框架都是ASP.NET WebForm.其實不管是MVC還是WebForm,在請求處理機制上,大部分是相同的。這涉及到IIS對請求的處理,涉及的知識較多,我們就不做介紹了,下次有機會我寫一篇專文。我們從HttpApplication說起。先看看微軟官方是怎么定義HttpApplication的:
定義 ASP.NET 應用程序中的所有應用程序對象共有的方法、屬性和事件。此類是用戶在 Global.asax 文件中所定義的應用程序的基類。
可能我翻譯不是很準確,原文連接在這里:https://msdn.microsoft.com/en-us/library/system.web.httpapplication(v=vs.110).aspx
微軟官方文檔中Remark里有這么一段話:HttpApplication 類的實例是在 ASP.NET 基礎結構中創建的,而不是由用戶直接創建的。使用 HttpApplication 類的一個實例來處理其生存期中收到的眾多請求。但是,它每次只能處理一個請求。這樣,成員變量才可用于存儲針對每個請求的數據。
意思就是說ASP.NET應用程序,不管是MVC還是WebForm,最終都會到達一個HttpApplication類的實例。HttpApplication是整個ASP.NET基礎架構的核心,負責處理分發給他的請求。HttpApplication處理請求的周期是一個復雜的過程,在整個過程中,不同階段會觸發相映的事件。我們可以注冊相應的事件,將處理邏輯注入到HttpApplication處理請求的某個階段。在HttpApplication這個類中定義了19個事件來處理到達HttpApplication實例的請求。就是說不管MVC還是WebForm,最終都要經過這19個事件的處理,那么除了剛才說的MVC和WebFrom在請求處理機制上大部分都是相同的,不同之處在哪呢?他們是從哪里開始分道揚鑣的呢?我們猜想肯定就在這19個方法中。我們繼續往下看。
我們來看看這19個事件:
應用程序按照以下順序執行由 global.asax 文件中定義的模塊或用戶代碼處理的事件:
事件名稱: | 簡單描述: |
BeginRequest | 在 ASP.NET 響應請求時作為 HTTP 執行管線鏈中的第一個事件發生 |
AuthenticateRequest | 當安全模塊已建立用戶標識時發生。注:AuthenticateRequest 事件發出信號表示配置的身份驗證機制已對當前請求進行了身份驗證。預訂 AuthenticateRequest 事件可確保在處理附加的模塊或事件處理程序之前對請求進行身份驗證 |
PostAuthenticateRequest | 當安全模塊已建立用戶標識時發生。PostAuthenticateRequest 事件在 AuthenticateRequest 事件發生之后引發。預訂 PostAuthenticateRequest 事件的功能可以訪問由 PostAuthenticateRequest 處理的任何數據 |
AuthorizeRequest | 當安全模塊已驗證用戶授權時發生。AuthorizeRequest 事件發出信號表示 ASP.NET 已對當前請求進行了授權。預訂 AuthorizeRequest 事件可確保在處理附加的模塊或事件處理程序之前對請求進行身份驗證和授權 |
PostAuthorizeRequest | 在當前請求的用戶已獲授權時發生。PostAuthorizeRequest 事件發出信號表示 ASP.NET 已對當前請求進行了授權。預訂PostAuthorizeRequest 事件可確保在處理附加的模塊或處理程序之前對請求進行身份驗證和授權 |
ResolveRequestCache | 當 ASP.NET 完成授權事件以使緩存模塊從緩存中為請求提供服務時發生,從而跳過事件處理程序(例如某個頁或 XML Web services)的執行 |
PostResolveRequestCache | 在 ASP.NET 跳過當前事件處理程序的執行并允許緩存模塊滿足來自緩存的請求時發生。)在 PostResolveRequestCache 事件之后、PostMapRequestHandler 事件之前創建一個事件處理程序(對應于請求 URL 的頁 |
PostMapRequestHandler | 在 ASP.NET 已將當前請求映射到相應的事件處理程序時發生。 |
AcquireRequestState | 當 ASP.NET 獲取與當前請求關聯的當前狀態(如會話狀態)時發生。 |
PostAcquireRequestState | 在已獲得與當前請求關聯的請求狀態(例如會話狀態)時發生。 |
PreRequestHandlerExecute | 恰好在 ASP.NET 開始執行事件處理程序(例如,某頁或某個 XML Web services)前發生。 |
PostRequestHandlerExecute | 在 ASP.NET 事件處理程序(例如,某頁或某個 XML Web service)執行完畢時發生。 |
ReleaseRequestState | 在 ASP.NET 執行完所有請求事件處理程序后發生。該事件將使狀態模塊保存當前狀態數據。 |
PostReleaseRequestState | 在 ASP.NET 已完成所有請求事件處理程序的執行并且請求狀態數據已存儲時發生。 |
UpdateRequestCache | 當 ASP.NET 執行完事件處理程序以使緩存模塊存儲將用于從緩存為后續請求提供服務的響應時發生。 |
PostUpdateRequestCache | 在 ASP.NET 完成緩存模塊的更新并存儲了用于從緩存中為后續請求提供服務的響應后,發生此事件。 |
LogRequest | 在 ASP.NET 完成緩存模塊的更新并存儲了用于從緩存中為后續請求提供服務的響應后,發生此事件。 僅在 IIS 7.0 處于集成模式并且 .NET Framework 至少為 3.0 版本的情況下才支持此事件 |
PostLogRequest | 在 ASP.NET 處理完 LogRequest 事件的所有事件處理程序后發生。 僅在 IIS 7.0 處于集成模式并且 .NET Framework 至少為 3.0 版本的情況下才支持此事件。 |
EndRequest | 在 ASP.NET 響應請求時作為 HTTP 執行管線鏈中的最后一個事件發生。 在調用 CompleteRequest 方法時始終引發 EndRequest 事件。 |
對于一個ASP.NET應用程序來說,HttpApplication派生與Global.aspx(可以看看我們創建的應用程序都有一個Global.aspx文件),我們可以在Global.aspx文件中對HttpApplication的請求進行定制即注入這19個事件中的某個事件進行邏輯處理操作。在Global.aspx中我們按照"Application_{Event Name}"這樣的方法命名進行事件注冊。
Event Name就是上面19個事件的名稱。比如Application_EndRequest就用于處理Application的EndRequest事件。
HttpModule
ASP.NET擁有一個高度可擴展的引擎,并且能夠處理對于不同資源類型的請求。這就是HttpModule。當一個請求轉入ASP.net管道時,最終負責處理請求的是與資源相匹配的HttpHandler對象,但是在HttpHandler進行處理之前,ASP.NET先會加載并初始化所有配置的HttpModule對象。HttpModule初始化的時候,會將一些回調事件注入到HttpApplication相應的事件中。所有的HttpModule都實現了IHttpModule接口,該接口有一個有一個Init方法。
public interface IHttpModule
{
// Methods
void Dispose();
void Init(HttpApplication context);
}看到Init方法呢接受一個HttpApplication對象,有了這個對象就很容易注冊HttpApplication中19個事件中的某個事件了。這樣當HttpApplication對象執行到某個事件的時候自然就會出發。
HttpHandler
對于不同的資源類型的請求,ASP.NET會加載不同的HttpHandler來處理。所有的HttpHandler都實現了IhttpHandler接口。
public interface IHttpHandler
{
// Methods
void ProcessRequest(HttpContext context);
// Properties
bool IsReusable { get; }
}我們看到該接口有一個方法ProcessRequest,顧名思義這個方法就是主要用來處理請求的。所以說每一個請求最終分發到自己相應的HttpHandler來處理該請求。
ASP.NET MVC 運行機制
好了,上面說了那么多,其實都是給這里做鋪墊呢。終于到正題了。先看看下面這張圖,描述了MVC的主要經歷的管道事件:

上圖就是一個完整的mvc應用程序的一個http請求到響應的整個兒所經歷的流程。從UrlRoutingModule攔截請求到最終ActionResult執行ExecuteResult方法生成響應。
下面我們就來詳細講解一下這些過程都做了些什么。
UrlRoutingModule
MVC應用程序的入口UrlRoutingModule
首先發起一個請求,我們前面講到ASP.NET 會加載一個HttpModule對象的初始化事件Init,而所有的HttpModule對象都實現了IHttpModule接口。我們看看UrlRoutingModule的實現:

從上圖中我們看到UrlRoutingModule實現了接口IHttpModule,當一個請求轉入ASP.NET管道時,就會加載 UrlRoutingModule對象的Init()方法。
那么為什么偏偏是UrlRoutingModule被加載初始化了呢?為什么不是別的HttpModule對象呢?帶著這個疑問我們繼續。
在ASP.NET MVC中,最核心的當屬“路由系統”,而路由系統的核心則源于一個強大的System.Web.Routing.dll組件。System.Web.Routing.dll 不是MVC所特有的,但是MVC框架和它是密不可分的。
首先,我們要了解一下UrlRoutingModule是如何起作用的。
(1)IIS網站的配置可以分為兩個塊:全局 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>
大家看到沒有,我上面標紅的那一行:<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
UrlRoutingModule并不是MVC特有的,這是一個全局配置,就是說所有的ASP.NET請求都會到達這里,所以該Module還不能最終決定是MVC還是WebForm請求。但是也是至關重要的地方。
(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源碼里面是怎么實現Init方法的,Init()方法里面我標注紅色的地方:
application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
這一步至關重要哈,看到沒有,就是對我們在HttpApplication那19個事件中的PostResolveRequestCache事件的注冊。注冊的方法是OnApplicationPostResolveRequestCache事件。也就是說HttpApplication對象在執行到PostResolveRequestCache這個事件的時候,就會執行OnApplicationPostResolveRequestCache事件。決定是MVC機制處理請求的關鍵所在就是OnApplicationPostResolveRequestCache事件。
從源碼中我們看出,OnApplicationPostResolveRequestCache事件執行的時候,最終執行了PostResolveRequestCache這個方法。最關鍵的地方呢就在這里了。
當請求到達UrlRoutingModule的時候,UrlRoutingModule取出請求中的Controller、Action等RouteData信息,與路由表中的所有規則進行匹配,若匹配,把請求交給IRouteHandler,即MVCRouteHandler。我們可以看下UrlRoutingModule的源碼來看看,以下是幾句核心的代碼:
我們再分析一下這個方法的源碼:
public virtual void PostResolveRequestCache(HttpContextBase context)
{
// 通過RouteCollection的靜態方法GetRouteData獲取到封裝路由信息的RouteData實例
RouteData routeData = this.RouteCollection.GetRouteData(context);
if (routeData != null)
{
// 再從RouteData中獲取MVCRouteHandler
IRouteHandler routeHandler = routeData.RouteHandler;
......
if (!(routeHandler is StopRoutingHandler))
{
......
// 調用 IRouteHandler.GetHttpHandler(),獲取的IHttpHandler 類型實例,它是由 IRouteHandler.GetHttpHandler獲取的,這個得去MVC的源碼里看
IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
......
// 合適條件下,把之前將獲取的IHttpHandler 類型實例 映射到IIS HTTP處理管道中
context.RemapHandler(httpHandler);
}
}
}看到了吧,通過路由規則,返回的不為空,說明匹配正確,關于路由規則的匹配,說起來也不短,這里就不大幅介紹,有時間下次再開篇詳解路由機制。匹配成功后,返回一個RouteData類型的對象,RouteData對象都有些什么屬性呢?看看這行源碼: IRouteHandler routeHandler = routeData.RouteHandler;或者看源碼我們知道,RouteDate有一個RouteHandler屬性。

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

我們看看我們新建的MVC應用程序,在App_Start文件夾下面有一個RouteConfig.cs類,這個類的內容如下:
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 }
);
}
}
}我們在這個類里面,主要是給路由表添加路由規則。在看看上面的UrlRoutingModule類,里面有一個RoutCollection屬性,所以UrlRoutingModule能夠獲取路由表中的所有規則,這里值得注意的是,路由規則的匹配是有順序的,如果有多個規則都能夠匹配,UrlRoutingModule至選擇第一個匹配的規則就返回,不再繼續往下匹配了。相反的如果一個請求,沒有匹配到任何路由,那么該請求就不會被處理。
這里返回的RouteData里的RouteHandler就是MVCRouteHandler。為什么呢?那我們繼續往下看RouteHandler。
RouteHandler
生成MvcHander
在上面路由匹配的過程中,與匹配路由相關聯的MvcRouteHandler ,MvcRouteHandler 實現了IRouteHandler 接口。MvcRouteHandler 主要是用來獲取對MvcHandler的引用。MvcHandler實現了IhttpHandler接口。
MVCRouteHandler的作用是用來生成實現IHttpHandler接口的MvcHandler。而我們前面說過最終處理請求的都是相對應的HttpHandler。那么處理MVC請求的自然就是這個MvcHandler。所以這里返回MvcRouteHandler至關重要:
那么,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 }
);
}
}看看我上面標紅的代碼:這是路由注冊,玄機就在這里。那我們去看看MapRoute源碼就知道咯:
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應用程序里,在路由注冊的時候,我們就已經給他一個默認的HttpRouteHandler對象,就是 New MvcRouteHandler().現在我們反推回去,我們MVC程序在路由注冊的時候就已經確定了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的方法,恰好就調用了這個方法。那我們看看MvcRouteHandler是怎么實現這個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行代碼,這時候應該明白了吧。順理成章的返回了MvcHandler對象。記得我們前面說過,請求最終是被相對應的HttpHander對象處理的。MvcHandler就是那個用來處理Mvc請求的HttpHandler。MvcRouteHandler把請求交給了MvcHandler去做請求處理管道中后續事件的處理操作了。
下面我們就看看MvcHandler做了些什么:
MvcHandler
MvcHandler就是最終對request進行處理。
MvcHandler的定義如下:

我們可以看到MvcHandler就是一個普通的Http Handler.我們知道一個http handler需要實現一個ProcessRequest()的方法,這個方法就是處理request的核心。所以MvcHandler實現了ProcessRequest()方法。
ProcessRequest主要功能:
(1)在ASP.NET MVC中,會調用MvcHandler的ProcessRequest()方法,此方法會激活具體請求的Controller類對象,觸發Action方法,返回ActionResult實例。
(2)如果ActionResult是非ViewResult,比如JsonResult, ContentResult,這些內容將直接被輸送到Response響應流中,顯示給客戶端;如果是ViewResult,就會進入下一個渲染視圖環節。
(3)在渲染視圖環節,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);
}
});
}從上面的代碼可以看出調用了一個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()方法中首先創建了ControllerFactory()的對象 factory.然后ControllerFactory創建了相關Controller的實例.最終調用了Controller的Excute()方法。
好我們再來看看ControllerFactory:
ControllerFactory
主要是用來生成Controller對象
ControllerFactory實現了接口IControllerFactory.
Controller
到這里我們大概就知道了,MvcHandler通過ProcessRequest()方法最終創建了Controller對象,這里我們都應該知道,Controller里面包含很多的Action方法,每一次請求至少一個Action方法會被調用。為了明確的實現IController接口,框架里面有一個ControllerBase的類已經實現了IController接口,其實我們自己的Controller也可以不繼承ControllerBase,只要實現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來調用Action方法的,當Controller對象被創建后,會執行Controller對象的基類ControllerBase類里面的Excute方法。Excute方法又調用了ExcuteCore()方法。Controller類里面實現了ExcuteCore()方法。ExcuteCore調用了ActionInvoker的InvokerAction方法來調用Action方法。
ActionInvoker
ActionInvoker方法有很重要的責任來查找Controller中的Action方法并且調用。

ActionInvoker是一個實現了IActionInvoker接口的對象:
bool InvokeAction( ControllerContext controllerContext, string actionName )
Controller類里面暴露了一個ActionInvoker 屬性,會返回一個ControllerActionInvoker 。ActionInvoker通過CreateActionInvoker()方法來創建ControllerActionInvoker對象。
public IActionInvoker ActionInvoker {
get {
if (_actionInvoker == null) {
_actionInvoker = CreateActionInvoker();
}
return _actionInvoker;
}
set {
_actionInvoker = value;
}
}
protected virtual IActionInvoker CreateActionInvoker() {
return new ControllerActionInvoker();
}我們看到CreateActionInvoker()是一個Virtual方法,我們可以實現自己的ActionInvoker.
ActionInvoker類需要匹配Controller中詳細的Action來執行,而這些詳細的信息是由ControllerDescriptor 提供的。ControllerDescriptor 和ActionDescriptor在ActionInvoker中扮演重要的角色。這兩個分別是對Controler和Action的詳細描述。ControllerDescriptor 描述了Controller的相關信息比如name,action,type等。
ActionDescriptor 描述了Action相關的詳情,比如name,controller,parameters,attributes和fiflters等。
ActionDescriptor 中一個中要的方法就是FindAction(),這個方法返回一個ActionDescriptor 對象,所以ActionInvoker知道該調用哪個Action。
ActionResult
到目前為止,我們看到了Action方法被ActionInvoker調用。所有的Action方法有一個特性,就是返回一個ActionResult類型的數據。
public abstract class ActionResult
{
public abstract void ExecuteResult(ControllerContext context);
}ExecuteResult()是一個抽象方法,所以不同的子類可以提供不同的ExecuteResult()實現。
ActionResult執行后響應輸出到客戶端。
ViewEngine
ViewResult幾乎是大部分應用程序的返回類型,主要通過ViewEngine引擎來展示view的。ViewEngine可能主要就是生成Html元素的引擎。Framwork提供了2種引擎,Razor View Engine 和Web Form View Engine.如果你想自定義引擎,你可以創建一個引擎只要實現IViewEngine接口即可。

IViewEngine 有下面幾個方法:
1、FindPartialView :當controller需要返回一個PartialView的時候,FindPartialView方法 就會被調用。
2、FindView
3、ReleaseView :主要用來有ViewEngine釋放資源
ViewResultBase 和ViewResult是比較重要的兩個類。ViewResultBase 包含下面的實現代碼:
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 ViewResultprotected 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被調用后,ViewResultBase 的ExecuteResult 方法被調用,然后ViewResultBase 調用ViewResult的FindView 。緊接著ViewResult 返回ViewEngineResult,之后ViewEngineResult調用Render()方法來繪制html輸出響應。
關于“asp.net MVC應用程序生命周期的示例分析”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。