asp.net mvc源碼分析-路由篇 如何找到 IHttpHandler

來源:互聯網
上載者:User

學習是使用asp.net已經有很長一段時間了,現在就來分析一下mvc的整過過程吧。個人排程寫一個mvc系列的博文,僅從原始碼的角度來分析mvc。在接觸mvc時我們一定會經曆路由,那麼路由這東東是怎麼搞出來的啊。在我們的web.config中有這麼一句:    <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 看來路由是它咋負責了。在這個dll中有一個很特殊的類UrlRoutingModule

我們來看看它裡面主要的核心代碼吧:

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)    {        HttpContextBase context = new HttpContextWrapper(((HttpApplication) sender).Context);        this.PostResolveRequestCache(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.CurrentUICulture, 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);                }            }        }    }

在IHttpModule.Init中註冊了一個PostResolveRequestCache事件,而該事件主要是調用PostResolveRequestCache這個方法,在這個方法裡面有幾句很重要的代碼是

  RouteData routeData = this.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);

讓我們來分析第一句RouteData routeData = this.RouteCollection.GetRouteData(context) ,這句我們猜測是擷取路由資訊。要想理解這句代碼又得回到我們程式中來,我們在Global.asax.cs檔案中的RegisterRoutes方法中,預設有這麼一句

 routes.MapRoute(
                "Default", // 路由名稱
                "{controller}/{action}/{id}", // 帶有參數的 URL
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 參數預設值
            );

這句代碼主要是註冊一個路由,這裡的url要注意不能隨便寫,需要有controller和action。具體是怎麼實現的了?

 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()            };            if ((namespaces != null) && (namespaces.Length > 0)) {                route.DataTokens["Namespaces"] = namespaces;            }            routes.Add(name, route);            return route;        }

各參數如下

routeName="Default", // 路由名稱
routeUrl= "{controller}/{action}/{id}", // 帶有參數的 URL
defaults=new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 參數預設值
constraints=null
namespaces=null

在這裡建立了一個Route執行個體並且把它加入到RouteCollection中了。

如果我們的項目中有特殊的需要,需要建立自己的HttpHandler這麼辦了?

其實很簡單只要我們註冊自己的IRouteHandler了,routes.Add(new Route("{controller}/{action}/{id}",new MvcRouteHandler())); 然後在裡面GetHttpHandler實現自己的邏輯處理

現在又讓我們回到 RouteData routeData = this.RouteCollection.GetRouteData(context);這句代碼中來,GetRouteData的主要代碼如下:

 public RouteData GetRouteData(HttpContextBase httpContext)
{
     using (this.GetReadLock())
        {
            foreach (RouteBase base2 in this)
            {
                RouteData routeData = base2.GetRouteData(httpContext);
                if (routeData != null)
                {
                    return routeData;
                }
            }
        }
    return null;
}
在這裡的base2就是我們先前調用MapRoute是添加的Route的。而Route的GetRouteData的方法如下:

public override RouteData GetRouteData(HttpContextBase httpContext){    string virtualPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;    RouteValueDictionary values = this._parsedRoute.Match(virtualPath, this.Defaults);    if (values == null)    {        return null;    }    RouteData data = new RouteData(this, this.RouteHandler);    if (!this.ProcessConstraints(httpContext, values, RouteDirection.IncomingRequest))    {        return null;    }    foreach (KeyValuePair<string, object> pair in values)    {        data.Values.Add(pair.Key, pair.Value);    }    if (this.DataTokens != null)    {        foreach (KeyValuePair<string, object> pair2 in this.DataTokens)        {            data.DataTokens[pair2.Key] = pair2.Value;        }    }    return data;}

這個方法很複雜,有許多驗證和檢查,我們主要關心一句 RouteData data = new RouteData(this, this.RouteHandler);

當然剩下 RequestContext requestContext = new RequestContext(context, routeData);
  context.Request.RequestContext = requestContext;這2句沒什麼特別了。

現在讓我們來看看IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);這句究竟幹了些什麼,意思很明白擷取Httphandler。

那麼MvcRouteHandler是如何擷取一個Httphandler的了,
        protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext) {
            requestContext.HttpContext.SetSessionStateBehavior(GetSessionStateBehavior(requestContext));
            return new MvcHandler(requestContext);
        }

直接返回了一個MvcHandler執行個體。

最有一句context.RemapHandler(httpHandler); 很簡單很好明白吧,在HttpContext的RemapHandler方法中有這麼一句 this._remapHandler = handler;

在HttpContext中有這個屬性

 internal IHttpHandler RemapHandlerInstance
    {
        get
        {
            return this._remapHandler;
        }
    }

那麼這個東西又是什麼時候調用的了,在HttpApplication的內部類MaterializeHandlerExecutionStep中的  void HttpApplication.IExecutionStep.Execute()方法調用

 if (httpContext.RemapHandlerInstance != null)
        {
            httpContext.Handler = httpContext.RemapHandlerInstance;
        }

看到MaterializeHandlerExecutionStep這個了類名,我想大家都能猜到吧。在內部類PipelineStepManager中BuildSteps方法有

 HttpApplication.IExecutionStep step = new HttpApplication.MaterializeHandlerExecutionStep(app);
            app.AddEventMapping("ManagedPipelineHandler", RequestNotification.MapRequestHandler, false, step);

我想大家看到這裡對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.