• Web Api实践系列(三)route特性使用


    一、webapi 路由机制

    ASP.NET Web API路由,简单来说,就是把客户端请求映射到对应的Action上的过程。在"ASP.NET Web API实践系列03,路由模版, 路由惯例, 路由设置"一文中,体验了通过模版、惯例、HTTP方法来设置路由,这种做法的好处是把路由模版统一放在了App_Start文件夹下的WebApiConfig类中,方便管理,但缺点是不够灵活。 

    REST把一切都看成资源,有时候,一个资源连带子资源,比如Customer和Orders密切关联,我们可能希望输入这样的请求:customers/1/orders,但仅仅凭借惯例,很难实现这种路由。而实际上,ASP.NET Web API为我们准备了Route特性,该特性可以直接打到Action上,使用非常灵活、直观。

    二、使用Route特性

    在webapi 2中不用修改任何配置,直接可以使用Route 特性,而在webapi1中需要修改WebApiConfig(具体修改配置本章不讲),下面结合实例演示一下使用Route特性

    首先创建一个Customer类

     public class Customer
        {
            public int Id { get; set; }
            public string Name { get; set; }
        }

    再创建一个Order类

    public class Order
        {
            public int Id { get; set; }
            public decimal Total { get; set; }
            public int CustomerId { get; set; }
            public Customer Customer { get; set; }
        }

    再创建一个Order集合类

     public class DatabaseTest
        {
            public static IEnumerable<Order> GetOrdersByCustomerId(int customerId)
            {
                return GetOrders().Where(o => o.CustomerId == customerId);
            }
    
    
            private static IEnumerable<Order> GetOrders()
    
            {
                Customer cus1 = new Customer() { Id = 1, Name = "张三" };
                Customer cus2 = new Customer() { Id = 2, Name = "李四" };
                List<Order> orders = new List<Order>()
                {
                    new Order(){Id = 1, Total = 80M, CustomerId = 1, Customer = cus1},
                    new Order(){Id = 2, Total = 100M, CustomerId = 1, Customer = cus1},
                    new Order(){Id = 3, Total = 120M, CustomerId = 2, Customer = cus2}
                };
                return orders;
            }
        }

    接下来创建一个空的api控制器OrderController,并写入一下代码

    namespace WebApiRout.Controllers
    {
        //[RoutePrefix("api")]
        public class OrdersController : ApiController
        {
            [Route("customers/{customerId}/orders")]
            [HttpGet]
            public IEnumerable<Order> FindOrdersByCustomer(int customerId)
            {
                return DatabaseTest.GetOrdersByCustomerId(customerId);
            }
        }
    }

    重点讲解一下OrderController中的route特性

    1.[Route("customers/{custimerId/orders}")]可以接受请求为 http://localhost/customers/1/orders

    2.如果启用[RoutePrefix("api")] 那该方法可接受的请求变为  http://localhost/api/customers/1/orders

    讲到这里就一目了然了,这两个特性的作用很明显了,各司其职!

    三、路由约束

    先了解一下webapi内置的约束有哪些

    {x:alpha} 约束大小写英文字母
    
    {x:bool}
    
    {x:datetime}
    
    {x:decimal}
    
    {x:double}
    
    {x:float}
    
    {x:guid}
    
    {x:int}
    
    {x:length(6)}
    
    {x:length(1,20)} 约束长度范围
    
    {x:long}
    
    {x:maxlength(10)}
    
    {x:min(10)}
    
    {x:range(10,50)}
    
    {x:regex(正则表达式)}

    路由约束举例

    //可以通过"{参数变量名称:约束}"来约束路由中的参数变量。
    [Route("users/{id:int}"]
    
    public User GetUserById(int id) { ... }
    
    //可以为一个参数变量同时设置多个约束
    [Route("users/{id:int:min(1)}")]
    
    public User GetUserByName(int id) { ... }
    
    //在约束后面加?,表示可选,在方法参数中给id设置默认值
    [Route("api/{id:int?}")]
    
    public IEnumerable<T> Get(int id = 8){}

    同样webapi提供了自定义路由约束,下面举例说明

    namespace WebApiRout.Models
    {
        /// <summary>
        /// 实现一个不能为0的路由约束
        /// </summary>
        public class MyHttpRouteConstraint : IHttpRouteConstraint
        {
            public bool Match(HttpRequestMessage request, IHttpRoute route,
                string parameterName, IDictionary<string, object> values, HttpRouteDirection routeDirection)
            {
                object value;
                //TryGetValue是获取指定键相关的值,并返回是否存在值truefalse
                if (values.TryGetValue(parameterName, out value) && value != null)
                {
                    long longValue;
                    if (value is long)
                    {
                        longValue = (long)value;
                        return longValue != 0;
                    }
                    string valueString = Convert.ToString(value, CultureInfo.InvariantCulture);
                    if (Int64.TryParse(valueString, NumberStyles.Integer,
                        CultureInfo.InvariantCulture, out longValue))
                    {
                        return longValue != 0;
                    }
                }
                return false;
    
            }
        }
    }
      public static class WebApiConfig
        {
            public static void Register(HttpConfiguration config)
            {
                // Web API 配置和服务
                // 将 Web API 配置为仅使用不记名令牌身份验证。
                config.SuppressDefaultHostAuthentication();
                config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
    
                // Web API 路由
                DefaultInlineConstraintResolver constraintResolver = new DefaultInlineConstraintResolver();
                constraintResolver.ConstraintMap.Add("MyHttpRouteConstraint", typeof(MyHttpRouteConstraint));
                config.MapHttpAttributeRoutes(constraintResolver);
    
    
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
            }
        }

     控制器代码

     //MyHttpRouteConstraint约束参数不能为0
            [Route("customers/{customerId:MyHttpRouteConstraint}/orders")]
            [HttpGet]
            public IEnumerable<Order> FindOrdersByCustomer(int customerId)
            {
                return DatabaseTest.GetOrdersByCustomerId(customerId);
            }

    此时请求结果如图

    四、路由优先顺序

    Route特性设置的路由优先顺序是根据惯例和RouteOrder属性来确定的。

     

    惯例是:

    1、静态片段变量
    2、带约束的片段变量
    3、不带约束的片段变量
    4、带约束的通配符片段变量
    5、不带约束的通配符片段变量

     

    RouteOrder属性的默认值是0,属性值越小,排在越前面。

     

    [RoutePrefix("orders")]
    
    public class OrdersController : ApiController
    
    {
    
        [Route("{id:int}")] // constrained parameter
    
        public HttpResponseMessage Get(int id) { ... }
    
    
    
        [Route("details")]  // literal
    
        public HttpResponseMessage GetDetails() { ... }
    
    
    
        [Route("pending", RouteOrder = 1)]
    
        public HttpResponseMessage GetPending() { ... }
    
    
    
        [Route("{customerName}")]  // unconstrained parameter
    
        public HttpResponseMessage GetByCustomer(string customerName) { ... }
    
    
    
        [Route("{*date:datetime}")]  // wildcard
    
        public HttpResponseMessage Get(DateTime date) { ... }
    
    }
    

    以上,路由的优先顺序是:

    orders/details  静态片段变量,RouteOrder属性值为0
    orders/{id} 带约束的片段变量,RouteOrder属性值为0
    orders/{customerName} 不带约束的片段变量,RouteOrder属性值为0
    orders/{*date} 带约束的通配符片段变量,RouteOrder属性值为0
    orders/pending RouteOrder属性值为1

  • 相关阅读:
    Android App Bundle 使用指南
    Homebrew国内源
    Mac下配置环境变量不生效问题
    CocosCreator1.x配置打包Android App Bundle
    Android读取Json文件的工具类
    Cocos Creator 坐标转换
    XCode真机调试不了,提示"Please reconnect the device"
    Canvas: trying to draw too large(134374464bytes) bitmap.
    Modbus主从关系几点记录
    当前时间加上几天
  • 原文地址:https://www.cnblogs.com/xqdotnet/p/6701065.html
Copyright © 2020-2023  润新知