asp.net MVC 應用程式的生命周期

来源:http://www.cnblogs.com/canfengfeixue/archive/2017/12/13/8035311.html
-Advertisement-
Play Games

首先我們知道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 = 	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Object proxy:當前對象,即代理對象!在調用誰的方法! Method method:當前被調用的方法(目標方法) Object[] args:實參! 案例2: ...
  • 示例: 生成命令 person Mac$ javadoc -d . -version -author Person.java 註意Person.java路徑名要正確。 效果: 其中index.html為主頁,打開如下圖: ...
  • 增加的菜單欄效果圖如下: eclipse 中調整到 swt的design視圖下 控制項區域選擇Menu Controls 將Menu Bar拖動到視窗標題欄 將Cascaded Menu拖動到Menu Bar 依次將多個Menu Item加入到New SubMenu Separator是分隔符 也可以 ...
  • 1.1 編程與編程語言 1.1.1 編程語言 電腦的發明,是為了用機器解放人力,而編程的目的則是將人類的思想流程按照某種能夠被電腦識別的表達方式傳遞給電腦,從而達到讓電腦能夠像人腦一樣自動執行的效果。 編程即程式員根據需求把自己的思想流程按照某種編程語言的語法風格編寫下來,產出的結果就是包含 ...
  • 大家好,之前我們介紹了《IDEA環境下GIT操作淺析之一Idea下倉庫初始化與文件提交涉及到的基本命令》和《IDEA環境下GIT操作淺析之二-idea下分支操作相關命令》,本文是第3部分,承接這2篇文章,大家可以點擊回顧,下麵請看本篇正文。 一、本地倉庫初始化與遠程倉庫推送操作 Idea 基本環境配 ...
  • OAuth: OAuth(開放授權)是一個開放標準,允許用戶授權第三方網站訪問他們存儲在另外的服務提供者上的信息,而不需要將用戶名和密碼提供給第三方網站或分享他們數據的所有內容。 QQ登錄OAuth2.0:對於用戶相關的OpenAPI(例如獲取用戶信息,動態同步,照片,日誌,分享等),為了保護用戶數 ...
  • 1、C#的值類型 有幾個特點: 存儲在棧里 基於值類型的變數直接包含值(值類型存儲實際值)。 將一個值類型變數賦給另一個值類型變數時,將複製包含的值。 這與引用類型變數的賦值不同,引用類型變數的賦值只複製對對象的引用,而不複製對象本身。 所有的值類型均隱式派生自 System.ValueType。 ...
  • 註意事項 上一篇已經說明,這次就不一一說了,直接來正文; word內容 相關代碼 方法1 1 static void Main(string[] args) 2 { 3 string wordPathStr = @"C:\Users\user\Desktop\新建文件夾 (2)\openxml讀取表 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...