zoukankan      html  css  js  c++  java
  • ASP.NET MVC , ASP.NET Web API 的路由系统与 ASP.NET 的路由系统是怎么衔接的?

     

    ASP.NET MVC 的路由实际上是建立在 ASP.NET 的路由系统之上的.

    MVC 路由注册通常是这样的:

    RouteTable 是一个全局路由表, 它的 Routes 静态属性是一个 RouteCollection 类型的实例,而 RouteCollection 是一个继承自 Collection<RouteBase> 的子类, RouteBase 是 ASP.NET 路由系统定义的基类

    .

    RouteBase 有一个唯一的实现类:

    当我们通过如下方法注册一个路由时:

     

    实际是向全局路由表中添加了一个 Route 类型的实例,部分源码如下: 

        public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
        {
          ......
          Route route = new Route(url, (IRouteHandler) new MvcRouteHandler())
          {
        ......
          };
        ......
          routes.Add(name, (RouteBase) route);
          return route;
        }

    从源码中我们可以看到,添加 Route 对象的时候,直接传入了一个 MvcRouteHandler 类型的实例.

    我们知道, ASP.NET 的路由系统对路由的解析是通过一个注册的 HttpModule 对象实现对请求的拦截,然后为当前 Http 上下文动态映射一个 HttpHandler 对象, 而这个  HttpHandler 对象会接管对当前请求的处理并最终对请求予以响应.

    这个注册的 HttpModule 对象的类型叫做 UrlRoutingModule .

    我们可以在ASP.NET 的全局系统配置文件中找到它:

         <httpModules>
            ......
                <add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule"/>
               ......
            </httpModules>

    该类型在 PostResolveRequestCache 事件实现对请求的拦截:

     在拦截时,它做了这么几件事(部分源码省略):

        public virtual void PostResolveRequestCache(HttpContextBase context)
        {
          RouteData routeData = this.RouteCollection.GetRouteData(context);     
          IRouteHandler routeHandler = routeData.RouteHandler;
          IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
          context.RemapHandler(httpHandler);
        }

    1.遍历所有注册的路由,也就是所有添加到全局路由表中的 Route 类型的实例,通过调用它们的 GetRouteData 方法,拿到第一个匹配的 RouteData (路由数据);

    2.拿到路由数据中的 RouteHandler 对象, 其实就是 MvcRouteHandler 类型的实例;

    3.调用 MvcRouteHandler 的 GetHttpHandler 方法,拿到 HttpHandler.

    MvcRouteHandler 的 GetHttpHandler 方法源码如下:

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

    可以看到,直接 new 了一个 MvcHandler 类型的实例,

    最终,请求转交给这个 MvcHandler 类型的实例处理.

    ASP.NET Web API 是怎么与 ASP.NET 路由系统接轨的呢?

    我们知道, ASP.NET 的路由系统对路由的解析是通过一个注册的 HttpModule 对象实现对请求的拦截,然后为当前 Http 上下文动态映射一个 HttpHandler 对象, 而这个  HttpHandler 对象会接管对当前请求的处理并最终对请求予以响应.

    这一条不仅对 MVC 适用, 对 Web API 同样适用,因为他俩都是借助于 ASP.NET 的路由系统.

    区别在于 HttpHandler 的类型不一样而已.

    ASP.NET Web API 注册路由的代码通常是这样的:

                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new
                    {
                        id = RouteParameter.Optional
                    }
                );

    config.Routes 是一个 HttpRouteCollection 类型的实例,并且是只读的.

    只读的,就意味着只能在该实例所属的类的构造函数中初始化.

    我们知道,这个 config 是 HttpConfiguration 类型,它在 GlobalConfiguration 类中初始化.

    在它的初始化代码中,我们可以看到:

            private static Lazy<HttpConfiguration> CreateConfiguration()
            {
                return new Lazy<HttpConfiguration>(() =>
                {
                    HttpConfiguration config = new HttpConfiguration(new HostedHttpRouteCollection(RouteTable.Routes));
              ......return config;
                });
            }

    HttpConfiguration 实际是对 HostedHttpRouteCollection 的封装,而后者是对 RouteTable.Route 的封装. 即 ASP.NET 全局路由表的封装.

    所以说, HttpConfiguration 类型封装了 ASP.NET 的全局路由表. 它的 Routes 属性的实际类型是  HostedHttpRouteCollection

    我们再回头看 config.Routes.MapHttpRoute 方法 , 也就是 HostedHttpRouteCollection 类型的 MapHttpRoute 方法:

            public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler)
            {
                ......
                IHttpRoute route = routes.CreateRoute(routeTemplate, defaultsDictionary, constraintsDictionary, dataTokens: null, handler: handler);
                routes.Add(name, route);
                return route;
            }

    很简单,创建了一个路由,然后添加它.

    我们继续查看 HostedHttpRouteCollection 类型的 CreateRoute 方法:

        public override IHttpRoute CreateRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
        {
        ......
        return (IHttpRoute) new HostedHttpRoute(uriTemplate, defaults, constraints, dataTokens, handler); }

    返回了一个 HostedHttpRoute 类型的实例.

    我们可以把这个方法 和 上面 MVC 的 MapRoute 方法做比较:

    MVC:

        public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
        {
          ......
          Route route = new Route(url, (IRouteHandler) new MvcRouteHandler())
          {
        ......
          };
        ......
          routes.Add(name, (RouteBase) route);
          return route;
        }

    是不是非常像!不同的只是 MVC  new 的路由对象是 Route 类型,而 Web API new 的路由对象是 HostedHttpRoute 类型.

    讲到这里,其实 ASP.NET Web API 的路由系统还没有和 ASP.NET 的路由系统衔接起来,它们二者的关系仅仅体现在下面这句话:

    HttpConfiguration 实际是对 HostedHttpRouteCollection 的封装,而后者是对 RouteTable.Route 的封装. 即 ASP.NET 全局路由表的封装.

    但是,当 HostedHttpRoute 创建后,调用 HostedHttpRouteCollection 的 Add 方法添加时,衔接就真正开始了:

            public override void Add(string name, IHttpRoute route)
            {
                _routeCollection.Add(name, route.ToRoute());
            }
     

     _routeCollection 是 RouteCollection 类型,没看错,就是 ASP.NET 路由系统的 RouteCollection .

    所以,这句代码实际是向 ASP.NET 路由系统的路由集合中添加路由,目的就是为了让 UrlRoutingModule 能够拦截到匹配了 Web API 注册的路由的请求.

    但是,问题来了,从上面 MVC 的讲解中我们知道, ASP.NET 路由系统的 RouteCollection 是一个继承自 Collection<RouteBase> 的子类, RouteBase 是 ASP.NET 路由的基类,

    而 HostedHttpRoute 是实现了 IHttpRoute 接口的实例, 

    IHttpRoute  和 RouteBase 风马牛不相接啊!

    所以,添加时,Web API 通过 HostedHttpRoute  的 ToRoute 方法,将自己转成了 RouteBase 类型!!

    这个转化非常简单:

     public static Route ToRoute(this IHttpRoute httpRoute)
            {
           ...... HostedHttpRoute hostedHttpRoute = httpRoute as HostedHttpRoute; if (hostedHttpRoute != null) { return hostedHttpRoute.OriginalRoute; }
           ...... }

    问题又来了, HostedHttpRoute 类型的 OriginalRoute 是个什么鬼?当然,肯定是个 Route  类型,也就是说,它是一个 ASP.NET 路由系统定义的 Route 类型.那它是怎么来的呢?

    我们知道,在 Web API 注册路由时, MapHttpRoute 内部创建了一个 HostedHttpRoute 类型的实例,并且是直接 new 的.

    那么我们去看看 HostedHttpRoute 的构造函数:

            public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
            {
                ......
                OriginalRoute = new HttpWebRoute(uriTemplate, routeDefaults, routeConstraints, routeDataTokens, HttpControllerRouteHandler.Instance, this);
                ......
            }

    OriginalRoute 原来是一个 HttpWebRoute 类型,而 HttpWebRoute 则是 ASP.NET 路由系统定义的 Route 类型的子类.

    并且,创建 HttpWebRoute 类型的实例时,传入了一个 ASP.NET 路由系统定义的 IRouteHandler 类型的实例 : HttpControllerRouteHandler.Instance

    而 HttpControllerRouteHandler 的 GetHttpHandler 方法如下:

            /// <summary>
            /// Provides the object that processes the request.
            /// </summary>
            /// <param name="requestContext">An object that encapsulates information about the request.</param>
            /// <returns>
            /// An object that processes the request.
            /// </returns>
            protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
            {
                return new HttpControllerHandler(requestContext.RouteData);
            }

    返回了一个 HttpControllerHandler 类型的实例.

    HttpControllerHandler 类型的XML注释则非常清晰的解释了它的作用:

      /// 用于将 ASP.NET 请求传递给管道并写回结果。</summary>

    这里说的管道,自然就是 Web API 的消息处理管道了.

    总结:

    ASP.NET MVC 和 ASP.NET Web API 都是通过 UrlRoutingModule ,在 PostResolveRequestCache 事件实现对请求的拦截.

    拦截后,通过对HTTP上下文,路由等一系列处理后,

    MVC 创建了 MvcHandler 进行具体的请求处理及响应;

    Web API 创建了 HttpControllerHandler 进行具体的请求处理及响应.

  • 相关阅读:
    (转)UIMenuController的使用,对UILabel拷贝以及定制菜单
    (转)ios多线程开发——NSOperation详解
    IOS custom statusBar 思路
    objectiveC的@property(atomic, retain)对引用计数的影响
    A Generic Particle IO Library
    RenderMan与CG生产流程简述
    Maya Mesh Relaxation Deformer
    个人黄金市场交易记录/Personal Gold Market Operation Record
    Implementation of TLRW ReadWrite Lock
    给想雇佣我的人说的话/Some words to somebody who want to hire me.
  • 原文地址:https://www.cnblogs.com/refuge/p/10505565.html
Copyright © 2011-2022 走看看