zoukankan      html  css  js  c++  java
  • [Web API] Web API 2 深入系列(5) 特性路由

    目录

    1. 特性路由注册
    
    2. 路由解析
    
        - 生成DataTokens
    
        - 选择HttpController
    
        - 选择Action
    

    特性路由的目的在于更好的提供restful架构的接口,最近好忙(懒),所以更新速度慢.

    特性路由注册

    • [Route(模板)] :定义特性路由模板

      • 普通变量

      a/b/{c}

      • 缺省变量

      a/b/{c=d}

      • 变量约束

      a/b/{c:int:range(10,20)}

      • 通配符

      a/b/{*c:datetime}

    [RoutePrefix("api/demo")] :定义路由前缀

    路由解析

    通过IRoutePrefix/IHttpRouteInfoProvider,我们可以直接注册路由,映射到具体的Controller和Action.

    当调用MapHttpAttributeRoutes方法时,WebAPI会创建1个唯一的RouteCollectionRoute作为IHttpRoute并添加到路由表中.

    MapHttpAttributeRoutes方法:

    public static void MapHttpAttributeRoutes(HttpConfiguration configuration, IInlineConstraintResolver constraintResolver, IDirectRouteProvider directRouteProvider)
    {
        RouteCollectionRoute aggregateRoute = new RouteCollectionRoute();
        configuration.Routes.Add("MS_attributerouteWebApi", (IHttpRoute) aggregateRoute);
        Action<HttpConfiguration> previousInitializer = configuration.Initializer;
        configuration.Initializer = (Action<HttpConfiguration>) (config =>
        {
            previousInitializer(config);
            aggregateRoute.EnsureInitialized((Func<IReadOnlyCollection<IHttpRoute>>) (() =>
            {
                subRoutes = new SubRouteCollection();
                AttributeRoutingMapper.AddRouteEntries(subRoutes, configuration, constraintResolver, directRouteProvider);
                return subRoutes;
            }));
        });
    }
    

    RouteCollectionRoute是特性路由的HttpRoute对象,既是一个IHttpRoute对象,又是一个IHttpRoute集合.并且其中核心方法为GetRouteData(IHttpRoute其他接口都返回为null),

    internal class RouteCollectionRoute : IHttpRoute, IReadOnlyCollection<IHttpRoute>, IEnumerable<IHttpRoute>, IEnumerable
    {
        public IHttpRouteData GetRouteData(string virtualPathRoot, HttpRequestMessage request)
        {
          List<IHttpRouteData> httpRouteDataList = new List<IHttpRouteData>();
          //调用内部的SubRoutes对象
          foreach (IHttpRoute subRoute in (IEnumerable<IHttpRoute>) this.SubRoutes)
          {
            IHttpRouteData routeData = subRoute.GetRouteData(virtualPathRoot, request);
            httpRouteDataList.Add(routeData);
          }
          return (IHttpRouteData) new RouteCollectionRoute.RouteCollectionRouteData((IHttpRoute) this, httpRouteDataList.ToArray());
        }
    }
    

    在该方法中,我们发现RouteCollectionRoute调用了内部所有的SubRoutes对象.

    而其内部的SubRoutes类型实际为SubRouteCollection类型

    internal class SubRouteCollection : IReadOnlyCollection<IHttpRoute>, IEnumerable<IHttpRoute>, IEnumerable
    {
        private readonly List<IHttpRoute> _routes = new List<IHttpRoute>();
        private readonly List<RouteEntry> _entries = new List<RouteEntry>();
        public IReadOnlyCollection<RouteEntry> Entries{get;}
    }
    

    而SubRoutes的创建是在MapHttpAttributeRoutes方法定义,实际调用是在HttpServer的Send方法初始化的.

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        this.EnsureInitialized();
        //...
    }
    

    首先验证一下我们的特性路由注册位置(定义1个扩展方法)

    public static class RouteCollectionExt
    {
        public static IEnumerable<IHttpRoute> GetSubRoutes(this HttpRouteCollection routes)
        {
            var route = routes["MS_attributerouteWebApi"];
            var prop = route.GetType().GetProperty("SubRoutes", BindingFlags.Instance | BindingFlags.NonPublic);
            var subRoutes = prop.GetValue(route) as IEnumerable<IHttpRoute>;
            return subRoutes;
        }
    }
    

    生成DataTokens

    DataTokens这次发挥了一定的作用,同时也告诉我们该如何使用它. (在第1节中,我觉得DataTokens是个冗余设计)

    先看下DataTokens上有哪些东西.

    private static void ShowSubRoutesTokens(HttpRouteCollection routes)
    {
        foreach (var subRoute in routes.GetSubRoutes())
        {
            Console.WriteLine(subRoute.RouteTemplate);
            foreach (var dataToken in subRoute.DataTokens)
            {
                Console.WriteLine("{0,-12}{1}", dataToken.Key, dataToken.Value);
            }
            Console.WriteLine();
        }
    
    }
    

    截图:

    对于DataTokens的actions和precedence的属性,在DirectRouteBuilder的Build方法中实现

    其中actions表示该路由模板对应的actiondescription(在特性路由中,会为每个controller创建独立的一份子路由.)

    而precedence表示匹配的优先级,对于有约束的优先级高于无优先级.(约束分为常量,变量,通配符)

    在前2节中,我们讲了如何选择Action以及Controller.
    实际上,如果使用特性路由.选择的机制又有些变化.

    选择HttpController

    public virtual HttpControllerDescriptor SelectController(HttpRequestMessage request)
    {
        IHttpRouteData routeData = request.GetRouteData();
        if (routeData != null)
        {
            //在GetDirectRouteController内获取了特性路由对应的Controller,同时要求匹配的所有特性路由对应的Controller为同一个
            HttpControllerDescriptor directRouteController = DefaultHttpControllerSelector.GetDirectRouteController(routeData);
            return directRouteController;
        }
        //普通路由方式
        string controllerName = this.GetControllerName(request);
        //...
    }
    

    选择Action

    public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
    {
        var matchingActions = this.FindMatchingActions(controllerContext, false);
        //...
    }
    
    private List<ApiControllerActionSelector.CandidateActionWithParams> FindMatchingActions(HttpControllerContext controllerContext, bool ignoreVerbs = false)
    {
        //此处做特性路由判断
        IEnumerable<IHttpRouteData> subRoutes = controllerContext.RouteData.GetSubRoutes();
        return subRoutes == null ? 普通路由 : 特性路由;
    }
    

    备注:
    - 如果我们为特性路由指定了Name,则会自动创建一个IHttpRoute绑定到RouteCollection上.(这步是在HttpConfiguration初始化中最后做判断完成的)

    - 文章中的代码并非完整WebAPI代码,一般是经过自己精简后的.
    
    - 本篇内容使用MarkDown语法编辑
    

    首发地址:http://neverc.cnblogs.com/p/5975086.html

  • 相关阅读:
    PythonStudy——数据类型总结 Data type summary
    PythonStudy——可变与不可变 Variable and immutable
    PythonStudy——列表操作 List operatio
    PythonStudy——列表的常用操作 List of common operations
    PythonStudy——列表类型 List type
    PythonStudy——字符串扩展方法 String extension method
    PythonStudy——字符串重要方法 String important method
    AWT,Swing,RCP 开发
    JQuery插件机制
    最新知识网站
  • 原文地址:https://www.cnblogs.com/neverc/p/5975086.html
Copyright © 2011-2022 走看看