進入MVC處理通道

來源:互聯網
上載者:User

標籤:resource   string   virtual   整合   tin   isp   tran   事件   exe   

這一篇主要講如何通過Asp.net處理管道把請求交給MVC進行處理的(進入MVC處理通道)。

首先來看一下經典的Asp.net處理管道的生命週期。

 

我們知道一個ASP.NET應用程式可以有多個HttpModule,但是只能有一個HttpHandler,並且通過這個HttpHandler的BeginProcessRequest(或ProcessRequest)來處理並返回請求,查看聲明處理管道周期可知在MapHttpHandler這個周期將會根據請求的URL來查詢對應的HttpHandler,那麼它是如何尋找的呢。

尋找系統web.config中的httpModules配置節,在倒數第二行發現一個name為UrlRoutingModule-4.0的IHttpModule配置,這是尋找HttpHandler的關鍵之處。下面分析一下UrlRoutingModule的代碼:

    protected virtual void Init(HttpApplication application) {        if (application.Context.Items[_contextKey] != null) {            return;        }        application.Context.Items[_contextKey] = _contextKey;        application.PostResolveRequestCache += OnApplicationPostResolveRequestCache;    }    private void OnApplicationPostResolveRequestCache(object sender, EventArgs e) {        HttpApplication app = (HttpApplication)sender;        HttpContextBase context = new HttpContextWrapper(app.Context);        PostResolveRequestCache(context);    }    public virtual void PostResolveRequestCache(HttpContextBase context) {        RouteData routeData = RouteCollection.GetRouteData(context);……        IRouteHandler routeHandler = routeData.RouteHandler;        ……        RequestContext requestContext = new RequestContext(context, routeData);        context.Request.RequestContext = requestContext;        IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);        ……        context.RemapHandler(httpHandler);}

可以看到UrlRoutingModule設定了一個PostResolveRequestCache事件處理方法,該方法從RouteCollection通過匹配找到請求對應的路由資料RouteData(包含如Mvc中的Controller名、Action名等),然後從RouteData的屬性RouteHandler擷取一個IRouteHandler的執行個體,再從IRouteHandler執行個體裡擷取對應的IHttpHandler執行個體,最後調用HttpContext的RemapHandler方法重新為HttpContext設定RemapHandlerInstance。

根據前面asp.net初始化流程分析2我們知道在擷取Httphandler時傳統模式和整合模式使用了不同的IExecutionStep,傳統模式用的是MapHandlerExecutionStep整合模式用的是MaterializeHandlerExecutionStep,查看二者的執行方法Execute。

先看MaterializeHandlerExecutionStep。

    void IExecutionStep.Execute() {        HttpContext context = _application.Context;        HttpRequest request = context.Request;        IHttpHandler handler = null;        string configType = null;        ……        if (context.RemapHandlerInstance != null){            wr.SetScriptMapForRemapHandler();            context.Handler = context.RemapHandlerInstance;        }……}

可以看到MaterializeHandlerExecutionStep中如果UrlRoutingModule模組中在HttpContext設定了RemapHandlerInstance,則直接用RemapHandlerInstance設定HttpContext的Handler。

再看MapHandlerExecutionStep。

    void IExecutionStep.Execute() {        HttpContext context = _application.Context;        HttpRequest request = context.Request;        ……        context.Handler = _application.MapHttpHandler(context, request.RequestType, request.FilePathObject, request.PhysicalPathInternal, false /*useAppConfig*/);        ……} 

在MapHandlerExecutionStep中會調用HttpApplication的MapHttpHandler方法來設定HttpContext的Handler。下面查看MapHttpHandler代碼:

    internal IHttpHandler MapHttpHandler(HttpContext context, String requestType, VirtualPath path, String pathTranslated, bool useAppConfig) {        IHttpHandler handler = (context.ServerExecuteDepth == 0) ? context.RemapHandlerInstance : null;        using (new ApplicationImpersonationContext()) {            if (handler != null){                return handler;        }        ……    }

從第一行代碼就可以看到如果HttpContext的RemapHandlerInstance不為空白則直接返回HttpContext的RemapHandlerInstance(context.ServerExecuteDepth是指頁面是否使用了HttpServerUtility.Execute進行頁面內跳轉)。這樣也就同樣使用了UrlRoutingModule模組中在HttpContext設定的RemapHandlerInstance,至於HttpContext沒有設定的RemapHandlerInstance的情況下如何根據預設的副檔名匹配尋找HttpHandler就不在此討論了。

通過上面的分析我們可以設想通過在UrlRoutingModule中的靜態RouteCollection屬性中註冊RouteData而且設定該RouteData的IRouteHandler(一個介面,只有一個方法GetHttpHandler用來擷取HttpHandler)來實現路由與HttpHandler的對應。下面來分析一下MvcHandler是如何通過路由註冊的,首先來看RouteCollection的實現

    public RouteCollection RouteCollection {        get {            if (_routeCollection == null) {                _routeCollection = RouteTable.Routes;            }            return _routeCollection;        }        set {            routeCollection = value;        }}

可以看到RouteCollection其實是封裝了RouteTable中的靜態Routes,如果有Mvc項目經驗的話應該很眼熟了,一般的Mvc程式在Global.asax中一般都有這麼一段用來註冊路由:

    protected void Application_Start()    {        ……        RouteConfig.RegisterRoutes(RouteTable.Routes);        ……    }    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 }            );        }    }

而我們定義的路由設定MvcHandler的奧妙正在MapRoute方法裡,這是一個擴充方法,定義在System.Web.Mvc.RouteCollectionExtensions裡:

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 = CreateRouteValueDictionaryUncached(defaults),            Constraints = CreateRouteValueDictionaryUncached(constraints),            DataTokens = new RouteValueDictionary()        };        ……        routes.Add(name, route);        return route;}

可以看到MapRoute註冊路由是綁定了一個MvcRouteHandler作為IRouteHandler,下面看MvcRouteHandler是如何?的:

    protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)    {        requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));        return new MvcHandler(requestContext);    }

在這裡終於看到了建立MvcHandler的代碼。

至此,我們應該有一個清晰的認識了,我們通過全域靜態屬性集合(RouteTable.Routes)去添加各種各樣的Route(但應該在HttpModule初始化周期之前,一般是利用HttpApplication建立的周期在Application_Start方法中添加了我們所需要的Route規則),當然在添加路由的時候帶上了MvcHandler這個重要的HttpHandler。然後通過UrlRoutingModule在PostResolveRequestCache周期通過尋找註冊的Route擷取請求的RouteData以及其屬性IRouteHandler執行個體(至於路由是如何匹配的還要等後續的篇章繼續講),然後通過IRouteHandler執行個體可以通過GetHttpHandler擷取IHttpHandler並將其設定到HttpContext的RemapHandlerInstance屬性。最終在MapHttpHandler周期通過擷取HttpContext的RemapHandlerInstance實現了不同的HttpHandler來接管匹配不同路由的URL。

至此對於進入MVC處理管道之前的一些處理基本講完了,下面就正式進入MVC的旅程,同時分析的主要代碼也進入了asp.net mvc項目。

進入MVC處理通道

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.