• [Web API] Web API 2 深入系列(1) 路由


    目录

    1. ASP.NET 路由

      • 注册路由

      • 动态映射HttpHandler

    2. WebAPI 路由

      • 注册路由

      • 调用GetRouteData

    3. 2个路由系统衔接

      • GlobalConfiguration

      • HostedHttpRoute

    4. 补充

    路由是进入Web API的第一扇门.目的用于确定Controller名称、Action名称、路由参数.

    ASP.NET 路由

    注册路由

    在ASP.NET中注册路由的方式:
    RouteCollection.MapPageRoute()

    添加1个完整的路由:

    var defaults = new RouteValueDictionary//路由变量默认值
    {
            {"code","010"},
            {"phone","1000000"},
    };
    var constraints = new RouteValueDictionary//路由变量约束
    {
        {"code",@"0d{2,3}" },
        {"phone",@"d{7,9}" },
        {"httpMethod",new HttpMethodConstraint("POST") }
    };
    var dataTokens = new RouteValueDictionary//路由相关参数,不用于处理路由匹配功能
    {
        {"defaultCode","北京" },
        {"defaultPhone","北京X电话" }
    };
    RouteTable.Routes.MapPageRoute("default", "{code}/{phone}", "~/call.aspx", false, defaults, constraints, dataTokens);
    

    获取RouteCollection

    一般通过RouteTable.Routes

    public class RouteTable
    {
        private static RouteCollection _instance = new RouteCollection();
     
        public static RouteCollection Routes { get { return RouteTable._instance; } }
    }
    

    路由:RouteBase

    public abstract class RouteBase
    {
      public bool RouteExistingFiles {get; set;} = true;//对现有文件进行路由
      public abstract RouteData GetRouteData(HttpContextBase httpContext);
      public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
    }
    

    路由默认实现:Route

    public class Route : RouteBase
    {
        /// <summary>
        /// 路由约束
        /// </summary>
        public RouteValueDictionary Constraints { get; set; }
        /// <summary>
        /// 路由自定义参数(一般存储备注说明等)
        /// </summary>
        public RouteValueDictionary DataTokens { get; set; }
        /// <summary>
        /// 路由变量默认值
        /// </summary>
        public RouteValueDictionary Defaults { get; set; }
        /// <summary>
        /// 路由对应处理程序对象
        /// </summary>
        public IRouteHandler RouteHandler { get; set; }
        /// <summary>
        /// 路由模板
        /// </summary>
        public string Url { get; set; }
    }
    

    忽略路由:
    忽略路由本质是添加一个StopRoutingHandler(返回空的HttpHandler)的路由

    routes.Ignore("010/1000001");(路由先注册,先匹配)
    routes.MapPageRoute("default", "{code}/{phone}", "~/call.aspx", false, defaults, constraints, dataTokens);
    

    路由约束:
    在上面完整的路由添加Demo中,路由约束有2种方式

    1. 正则表达式字符串
    2. 实现IRouteConstraint接口

    动态映射HttpHandler

    路由是通过UrlRoutingModule这个HttpModule实现动态拦截.

    public virtual void PostResolveRequestCache(HttpContextBase context)
    {
        RouteData routeData = RouteTable.Routes.GetRouteData(context);
        IRouteHandler routeHandler = routeData.RouteHandler;
        IHttpHandler httpHandler = routeHandler.GetHttpHandler(new RequestContext(context, routeData));
        context.RemapHandler(httpHandler);
    }
    

    WebAPI 路由

    注册路由

    在Web API中注册路由的方式:HttpRouteCollection.MapHttpRoute(),
    这里重点看下MapHttpRoute方法内部

    public static class HttpRouteCollectionExtensions
    {
        public static IHttpRoute MapHttpRoute(this HttpRouteCollection routes, string name, string routeTemplate, object defaults, object constraints, HttpMessageHandler handler)
        {
            IHttpRoute route = routes.CreateRoute(routeTemplate, (IDictionary<string, object>)defaults, (IDictionary<string, object>)constraints, (IDictionary<string, object>)null, handler);
            routes.Add(name, route);
            return route;
        }
    }
    

    获取HttpRouteCollection

    在WebAPI中通过HttpConfiguration的Routes属性

    public class HttpConfiguration : IDisposable
    {
        public Collection<DelegatingHandler> MessageHandlers { get; }
        public HttpRouteCollection Routes { get; }
        public ConcurrentDictionary<object, object> Properties { get; }
    }
    

    WebAPI路由:IHttpRoute

    public interface IHttpRoute
    {
      string RouteTemplate { get; }
     
      IDictionary<string, object> Defaults { get; }
     
      IDictionary<string, object> Constraints { get; }
     
      IDictionary<string, object> DataTokens { get; }
     
      HttpMessageHandler Handler { get; }
     
      IHttpRouteData GetRouteData(string virtualPathRoot, HttpRequestMessage request);
     
      IHttpVirtualPathData GetVirtualPath(HttpRequestMessage request, IDictionary<string, object> values);
    }
    

    WebAPI路由默认实现:HttpRoute
    由于IHttpRoute设计的非常全,HttpRoute基本就是实现了IHttpRoute.
    (这种设计上比RouteBase要优势很多)

    调用GetRouteData

    与ASP.NET稍微不同的是

    1. 直接对所有请求进行路由 而不再判断是否文件存在.
    2. 添加一个VirtualPathRoot的过滤
    public class HttpRouteCollection
    {
        public virtual IHttpRouteData GetRouteData(HttpRequestMessage request)
        {
            string virtualPathRoot = request.GetRequestContext().VirtualPathRoot;
            IHttpRouteData routeData = this._collection[index].GetRouteData(virtualPathRoot, request);
            return routeData;
        }
    }
    

    2个路由系统衔接

    Web API提供了一套自身的路由系统,所以不依赖于ASP.NET.

    寄宿方式有多种.如果以WebHost的方式.本质上还是走的ASP.NET路由处理.

    GlobalConfiguration

    WebAPI的配置在HttpConfiguration中提供.

    在WebHost中,定义了GlobalConfiguration用来创建HttpConfiguration

    public static class GlobalConfiguration
    {
    public static HttpConfiguration Configuration = GlobalConfiguration.CreateConfiguration();//创建HttpConfiguration

    public static HttpMessageHandler DefaultHandler = GlobalConfiguration.CreateDefaultHandler();//创建HttpRoutingDispatcher(WebAPI管道尾部HttpMessageHandler)
    
    public static HttpServer DefaultServer = GlobalConfiguration.CreateDefaultServer();//创建HttpServer(WebAPI管道开头HttpMessageHandler)
    
    public static void Configure(Action<HttpConfiguration> configurationCallback)//提供方便配置路由
    {
        configurationCallback(GlobalConfiguration.Configuration);
    }
    
    private static Lazy<HttpConfiguration> CreateConfiguration()
    {
        return new Lazy<HttpConfiguration>((Func<HttpConfiguration>) (() =>
        {
            //这里用HostedHttpRouteCollection实现HttpRouteCollection
            return new HttpConfiguration((HttpRouteCollection) new HostedHttpRouteCollection(RouteTable.Routes));
        }));
    }
    

    }

    HostedHttpRoute

    在GlobalConfiguration中创建的HttpConfiguration对象是用HostedHttpRouteCollection作为参数
    这里我觉得有必要看下CreateRoute和Add方法

    internal class HostedHttpRouteCollection : HttpRouteCollection
    {
        //真正维护的路由集合
        private readonly RouteCollection _routeCollection;
    
        //创建路由 MapHttpRoute会调用该方法
        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);
        }
    
        public override void Add(string name, IHttpRoute route)
        {
            //只是添加到内部的routeCollection中
            //route.ToRoute() => route.OriginalRoute;
          this._routeCollection.Add(name, (RouteBase) route.ToRoute());
        }
    
        public override IHttpRouteData GetRouteData(HttpRequestMessage request)
        {
            //通过调用内部的Route的GetRouteData
            RouteData routeData = this._routeCollection.GetRouteData(httpContextBase);
            return (IHttpRouteData)new HostedHttpRouteData(routeData);
        }
    }
    

    而HostedHttpRoute在WebHost中
    相当于用HttpRoute的身 却提供了真正的Route

    internal class HostedHttpRoute : IHttpRoute
    {
        //ASP.NET Route
        internal Route OriginalRoute { get; private set; }
    
        public HostedHttpRoute(string uriTemplate, IDictionary<string, object> defaults, IDictionary<string, object> constraints, IDictionary<string, object> dataTokens, HttpMessageHandler handler)
        {
            //内部的OriginalRoute实际为HttpWebRoute
          this.OriginalRoute = (Route) new HttpWebRoute(uriTemplate, defaults1, constraints1, dataTokens1, <strong>(IRouteHandler) HttpControllerRouteHandler.Instance</strong>, (IHttpRoute) this);
          this.Handler = handler;
        }
    }
    

    从HostedHttpRoute构造函数中 我们看到了真正的Route为HttpWebRoute 且RouteHandler为HttpControllerRouteHandler.Instance

    public class HttpControllerRouteHandler : IRouteHandler
    {
        public static HttpControllerRouteHandler Instance{ get { return new HttpControllerRouteHandler(); } }
     
        protected virtual IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return (IHttpHandler) new HttpControllerHandler(requestContext.RouteData);
        }
    }
    

    补充

    冗余的设计:

    • HttpRoute中Handler的HttpMessageHandler,未发现有任何地方使用到.

    • HttpRoute和Route中DataTokens,建议直接取消.

    备注:

    • 文章中的代码并非完整,一般是经过自己精简后的.

    • 本篇内容使用MarkDown语法编辑

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

  • 相关阅读:
    【SQL】oralce中使用group by和case when按照条件求和
    【SQL】ORACLE在sqlplus中使用spool方式生成建表语句
    【SQL】将特定的元素按照自己所需的位置排序
    【LeetCode刷题】SQL-Second Highest Salary 及扩展以及Oracle中的用法
    【LeetCode刷题】SQL-Combine Two Tables
    CSDN无故封我账号,转战博客园。
    Visual Studio 代码管理器svn插件下载
    Geoserver的跨域问题
    Jmeter+Ant+jenkins实现api自动化测试的持续集成
    python编程中的并发------多线程threading模块
  • 原文地址:https://www.cnblogs.com/neverc/p/5946240.html
Copyright © 2020-2023  润新知