zoukankan      html  css  js  c++  java
  • URL Routing组件是如何与ASP.NET MVC框架组合起来的

    最近有一段时间都在看ASP.NET MVC框架的源代码。原来的想法是,如果有相应ASP.NET MVC的文档,就直接看文档,学学怎么使用这个框架。可惜都是视频教程,而又感觉看那本电子书有点无趣,索性就直接看源代码了。这样一来反而收获了很多的东西。

    在ASP.NET MVC框架里面,用到了URL Routing组件。URL Routing组件干什么用呢?根据你配置的URL 模式来提取数据或者生成相应的URL 。但我有一个疑问:URL Routing组件是如何同ASP.NET MVC框架关联起来的?

    由于这个组件没有开放源代码,所以我们查看代码的方式也就只有反编译了。我们可以看到Route类型。这个类表示一条路由,包括URL模式,路由数据,HTTP处理程序等。我们可以看到它的构造器如下:

    public Route(string url, IRouteHandler routeHandler);
    public Route(string url, RouteValueDictionary defaults, IRouteHandler routeHandler);
    public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler);
    public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler);
    Route的初始化时需要一个实现IRouteHandler接口的类的实例的。IRouteHandler的定义如下:
     
    public interface IRouteHandler{
        IHttpHandler GetHttpHandler(RequestContext requestContext);
    }
    IRouteHandler只定义了一个方法——GetHttpHandler,返回一个IHttpHandler。IHttpHandler其实就是ASP.NET管线事件的终点,所有的HTTP请求最后都是由IHttpHandler的实现来处理的。

    沿着这个思路,我们继续往下找,看能不能找到一个实现这个接口的类型。一开始看到一个UrlRoutingHandler,以为找到要找的类型了,不过仔细一开类型的定义,是抽象类型,表示Routing的终点,因为这个抽象类实现了IHttpHandler接口。查看它的ProcessRequest方法的代码,如下:

    protected virtual void ProcessRequest(HttpContextBase httpContext)
    {
        RouteData routeData = this.RouteCollection.GetRouteData(httpContext);
        if (routeData == null)
        {
            throw new HttpException(0x194, SR.GetString("UrlRoutingHandler_NoRouteMatches"));
        }
        IRouteHandler routeHandler = routeData.RouteHandler;
        if (routeHandler == null)
        {
            throw new InvalidOperationException(SR.GetString("UrlRoutingModule_NoRouteHandler"));
        }
        RequestContext requestContext = new RequestContext(httpContext, routeData);
        IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
        if (httpHandler == null)
        {
            throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() }));
        }
        this.VerifyAndProcessRequest(httpHandler, httpContext);
    }
    可以看到,实际上这个方法首先使用Route的实例返回一个IRouteHandler接口实现类的实例对象,调用IRouteHandler.GetHttpHandler()方法返回一个IHttpHandler实现类的实例对象,最后调用了this.VerifyAndProcessRequest(httpHandler, httpContext)方法进行处理。VerifyAndProcessRequest(httpHandler, httpContext)定义如下:
     
    protected abstract void VerifyAndProcessRequest(
      IHttpHandler httpHandler, 
      HttpContextBase httpContext);
    这是一个抽象方法。URL Routing组件最后一定映射到一个处理程序来相应HTTP请求,显然,必定有一个实现类继承并且实现了这个VerifyAndProcessRequest方法。我们在这个组件里面接着找,还是没有找到相应的实现类型,但是我们发现了一个UrlRoutingModule类。这个类实现了IHttpModule,是一个ASP.NET模块。那么这个模块做了什么?我们可以查看这个模块的Init(HttpApplication application)方法,定义如下:
     
    protected virtual void Init(HttpApplication application)
    {
        if (application.Context.Items[_contextKey] == null)
        {
            application.Context.Items[_contextKey] = _contextKey;
            application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache);
        }
    }
     
    它订阅了ASP.NET的PostResolveRequestCache管线事件,并且这个方法重新映射了HTTP 处理程序,其实这个类型在.NET 3.5以及.NET 4.0中还是有所不同的。(this.OnApplicationPostResolveRequestCache方法代码如下:
    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);
                }
            }
        }
    }
     

    这个方法从Route实例取得RouteData,并且从RouteData获得相应的IHttpHandler处理程序来处理请求,这样,URL Routing最终把HTTP请求映射到一个处理程序处理。但是这里有个问题,就是这个处理程序的实例是什么时候初始化,又是如何初始化的?并且,URL Routing是怎么和ASP.NET MVC框架关联起来的?

     
    带着这个问题去看ASP.NET MVC框架的源代码,我们找到两个引人注意的类型:MvcHttpHandler以及MvcRouteHandler。MvcHttpHandler继承了UrlRoutingHandler, IHttpAsyncHandler, IRequiresSessionState,是一个HttpHandler。看来这个类型并不是我们要寻找的答案。于是,我想到是不是利用配置文件来把这两个组件关联起来的?于是我去看了Oxite的配置文件,注意到有这么一段配置:
    <httpHandlers>
      <remove verb="*" path="*.asmx"/>
      <add verb="*" path="*.asmx" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add verb="*" path="*_AppService.axd" validate="false" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" validate="false"/>
      <add verb="*" path="*.mvc" validate="false" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    </httpHandlers>
    <httpModules>
      <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
      <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
    </httpModules>
    这段配置还是没有解决我们的疑问。因为我们知道ASP.NET MVC框架必定在某一个地方创建了一个MvcHttpHandler的实例并且将这个实例传递给URL Routing组件,URL Routing最终将请求映射到这个处理程序,然后相应请求。联想到我们每一个路由都是有一个Route类型表示的,那么我们如何实例化这个类型?一般都是在Application_Start事件里初始化并且添加到路由表里面的吧?OK,也许问题的答案就在这个地方。我们添加路由的时候,记得都是用MapRoute这个拓展方法吧,这个方法非常方便,但是这个方法被定义在哪里?在找遍了URL Routing组件,我并没有发现有这样的这样的拓展方法。于是我想到可能又是放在了ASP.NET MVC框架里了。于是我在框架里发现了RouteCollectionExtensions这个类型,这个类型为RouteCollection定义了非常多的拓展方法,其中就包括MapRoute方法。在编写实现的时候,框架使用了串联的方式,也就是很多的重载方法,其实都是调用一个实现方法。这个实现方法如下:
    public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces) {
      if (routes == null) {
        throw new ArgumentNullException("routes");
      }
      if (url == null) {
        throw new ArgumentNullException("url");
      }
    
    
      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;
    }
     
    在兜了一圈,终于回来了。我们非常清楚的看到,是在这里,把MvcHttpHandler注入,也就将URL Routing和ASP.NET MVC关联起来了。

    总结

     
    这里只是整理我在看ASP.NET MVC框架源代码中,忽然想到的框架是如可和URL Routing组件关联起来这个问题的解题思路,绕了一圈才忽然明白,因此我将我的思路记录了下来。其实一句话,在初始化Route类型的时候就将IHttpHandler实例注入,这样就完成了关联了。
  • 相关阅读:
    4.10Python数据处理篇之Matplotlib系列(十)---文本的显示
    4.9Python数据处理篇之Matplotlib系列(九)---子图分布
    4.8Python数据处理篇之Matplotlib系列(八)---Figure的学习
    4.7Python数据处理篇之Matplotlib系列(七)---matplotlib原理分析
    4.6Python数据处理篇之Matplotlib系列(六)---plt.hist()与plt.hist2d()直方图
    4.5Python数据处理篇之Matplotlib系列(五)---plt.pie()饼状图
    4.4Python数据处理篇之Matplotlib系列(四)---plt.bar()与plt.barh条形图
    4.3Python数据处理篇之Matplotlib系列(三)---plt.plot()折线图
    Angular 定时器$timeout和$interval,延时调用
    javascript中top、clientTop、scrollTop、offsetTop的讲解(转载加总结)
  • 原文地址:https://www.cnblogs.com/jinacookies/p/1884590.html
Copyright © 2011-2022 走看看