重写RoutePrefix

    [RoutePrefix("api/orders")]
    public class OrdersController : ApiController
    {
        [Route("")]
        [HttpGet]
        public async Task<IHttpActionResult> GetOrders()
        {
            return Ok();
        }

        [Route("{customerId}")]
        [HttpGet]
        public async Task<IHttpActionResult> GetOrders(int customerId)
        {
            return Ok();
        }


        [Route("~/api/customers/{customerId}/orders")]
        [HttpGet]
        public async Task<IHttpActionResult> GetOrders2(int customerId)
        {
            return Ok();
        }
    }

上面的代码中获取某个用户的订单有两种路由方式,第一种显然是不好的,因为订单详情的路由有可能和这个一样,第二种方式就比较好了,通过url就可以清晰地知道请求的资源。

路由约束

ASP.NET Web API内置约束有下面这些

{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("api/orders/{id:int:min(1)}")]

还可以自定义约束,实现IHttpRouteConstraint接口

public class NonZeroConstraint : IHttpRouteConstraint
{
    public bool Match(HttpRequestMessage request, IHttpRoute route, string parameterName, 
        IDictionary<string, object> values, HttpRouteDirection routeDirection)
    {
        object value;
        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)
    {
        var constraintResolver = new DefaultInlineConstraintResolver();
        constraintResolver.ConstraintMap.Add("nonzero", typeof(NonZeroConstraint));
        config.MapHttpAttributeRoutes(constraintResolver);
    }
}

使用自定义约束

[Route("{id:nonzero}")]

路由顺序

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