首先我們知道http是一種無狀態的請求,他的生命周期就是從客戶端瀏覽器發出請求開始,到得到響應結束。那麼MVC應用程式從發出請求到獲得響應,都做了些什麼呢? 本文我們會詳細討論MVC應用程式一個請求的生命周期,從一個控制項到另一個控制項是怎樣被處理的。我們還會詳細介紹一下整個請求的生命周期中,用到的相關 ...
首先我們知道http是一種無狀態的請求,他的生命周期就是從客戶端瀏覽器發出請求開始,到得到響應結束。那麼MVC應用程式從發出請求到獲得響應,都做了些什麼呢?
本文我們會詳細討論MVC應用程式一個請求的生命周期,從一個控制項到另一個控制項是怎樣被處理的。我們還會詳細介紹一下整個請求的生命周期中,用到的相關組件。因為在平常的開發過程中,我們可能知道怎樣去使用MVC框架來處理相關的請求,大部分的時候我們只是在controller和action方法之間做相關的處理,對於真正內在的運行機制可能不是很瞭解。其實當我們對內在機制有了一定的瞭解以後,會發現微軟的MVC框架的擴展性很強,到處都留有擴展介面,讓我們通過擴展能夠自己定義自己所需要的處理機制,這也正是為什麼MVC框架如此出名的原因。
當我最開始學習使用mvc的時候,困擾我的一個問題就是,一個請求的流程式控制制是怎樣的呢?從view到controller再到action之間經歷了什麼?那個時候我還不清楚HTTP module和HTTP handler在處理一個請求中扮演什麼樣的角色,起什麼樣的作用呢。畢竟MVC是一個web開發框架,在整個請求處理過程中,肯定包含了http module和http handler。其實還有很多相關的組件包含在一個完整的mvc應用程式請求生命周期里,在整個請求過程中他們都扮演者非常重要的角色。儘管大部分時候我們都使用的是框架提供的預設的函數,但是如果我們瞭解了每個控制項所扮演的角色,我們就可以輕鬆的擴展和使用我們自己實現的方法,就目前來說MVC是擴展性比較強的框架。下麵是本章節的主要內容:
- HttpApplication
- HttpModule
- HttpHandler
- ASP.NET MVC運行機制
- UrlRoutingModule
- RouteHandler
- MvcHandler
- ControllerFactory
- Controller
- ActionInvoker
- ActionResult
- ViewEngine
HttpApplication
我們都知道,在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的源碼來看看,以下是幾句核心的代碼:
我們再分析一下這個方法的源碼:
1 public virtual void PostResolveRequestCache(HttpContextBase context)
2 {
3 // 通過RouteCollection的靜態方法GetRouteData獲取到封裝路由信息的RouteData實例
4 RouteData routeData = this.RouteCollection.GetRouteData(context);
5 if (routeData != null)
6 {
7 // 再從RouteData中獲取MVCRouteHandler
8 IRouteHandler routeHandler = routeData.RouteHandler;
9 ......
10 if (!(routeHandler is StopRoutingHandler))
11 {
12 ......
13 // 調用 IRouteHandler.GetHttpHandler(),獲取的IHttpHandler 類型實例,它是由 IRouteHandler.GetHttpHandler獲取的,這個得去MVC的源碼里看
14 IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
15 ......
16 // 合適條件下,把之前將獲取的IHttpHandler 類型實例 映射到IIS HTTP處理管道中
17 context.RemapHandler(httpHandler);
18 }
19 }
20 }
看到了吧,通過路由規則,返回的不為空,說明匹配正確,關於路由規則的匹配,說起來也不短,這裡就不大幅介紹,有時間下次再開篇詳解路由機制。匹配成功後,返回一個RouteData類型的對象,RouteData對象都有些什麼屬性呢?看看這行源碼: IRouteHandler routeHandler = routeData.RouteHandler;或者看源碼我們知道,RouteDate有一個RouteHandler屬性。
那麼UrlRouting Module是如何選擇匹配規則的呢?
我們看看我們新建的MVC應用程式,在App_Start文件夾下麵有一個RouteConfig.cs類,這個類的內容如下:
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Web;
5 using System.Web.Mvc;
6 using System.Web.Routing;
7
8 namespace ApiDemo
9 {
10 public class RouteConfig
11 {
12 public static void RegisterRoutes(RouteCollection routes)
13 {
14 routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
15
16 routes.MapRoute(
17 name: "Default",
18 url: "{controller}/{action}/{id}",
19 defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
20 );
21 }
22 }
23 }
我們在這個類裡面,主要是給路由表添加路由規則。在看看上面的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源碼就知道咯:
1 public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
2 {
3 ......
4
5 Route route = new Route(url, new MvcRouteHandler()) {
6 Defaults = new RouteValueDictionary(defaults),
7 Constraints = new RouteValueDictionary(constraints),
8 DataTokens = new RouteValueDictionary()
9 };
10 ......
11 return route;
12 }
看看我們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的呢:
1 public class MvcRouteHandler : IRouteHandler
2 {
3 // Fields
4 private IControllerFactory _controllerFactory;
5
6 // Methods
7 public MvcRouteHandler()
8 {
9 }
10
11 public MvcRouteHandler(IControllerFactory controllerFactory)
12 {
13 this._controllerFactory = controllerFactory;
14 }
15
16 protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
17 {
18 requestContext.HttpContext.SetSessionStateBehavior(this.GetSessionStateBehavior(requestContext));
19 return new MvcHandler(requestContext);
20 }
21
22 protected virtual SessionStateBehavior GetSessionStateBehavior(RequestContext requestContext)
23 {
24 string str = (string) requestContext.RouteData.Values["controller"];
25 if (string.IsNullOrWhiteSpace(str))
26 {
27 throw new InvalidOperationException(MvcResources.MvcRouteHandler_RouteValuesHasNoController);
28 }
29 IControllerFactory factory = this._controllerFactory ?? ControllerBuilder.Current.GetControllerFactory();
30 return factory.GetControllerSessionBehavior(requestContext, str);
31 }
32
33 IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)
34 {
35 return this.GetHttpHandler(requestContext);
36 }
37 }
38
39
看第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()定義如下:
1 // Copyright (c) Microsoft Open Technologies, Inc.<pre>// All rights reserved. See License.txt in the project root for license information.
2 void IHttpHandler.ProcessRequest(HttpContext httpContext)
3 {
4 ProcessRequest(httpContext);
5 }
6 protected virtual void ProcessRequest(HttpContext httpContext)
7 {
8 HttpContextBase iHttpContext =