3

我正在使用ASP.NET Web Api 2框架并使用下面的基本路由约束。如何设置ASP.NET Web Api路由约束HTTP状态返回代码

[Route("Number/{id:int:min(2):max(10)}")] 
    public HttpResponseMessage GetNumber([FromUri] int id) 
    { 
     return (id > 0) 
      ? Request.CreateResponse(HttpStatusCode.OK, id) 
      : Request.CreateResponse(HttpStatusCode.PreconditionFailed); 
    } 

我想知道什么时候id与上面的约束冲突,例如.e.g。 1或11, 如何覆盖404的默认HTTP状态返回码?

非常感谢。

回答

7

您可以创建一个自定义路由约束将检查分钟,像你这样的最大值希望,另外还允许您指定HttpStatusCode的情况下,约束不正确履行。

public class RangeWithStatusRouteConstraint : IHttpRouteConstraint 
{ 
    private readonly int _from; 
    private readonly int _to; 
    private readonly HttpStatusCode _statusCode; 

    public RangeWithStatusRouteConstraint(int from, int to, string statusCode) 
    { 
     _from = from; 
     _to = to; 
     if (!Enum.TryParse(statusCode, true, out _statusCode)) 
     { 
      _statusCode = HttpStatusCode.NotFound; 
     } 
    } 

    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) 
     { 
      var stringValue = value as string; 
      var intValue = 0; 

      if (stringValue != null && int.TryParse(stringValue, out intValue)) 
      { 
       if (intValue >= _from && intValue <= _to) 
       { 
        return true; 
       } 

       //only throw if we had the expected type of value 
       //but it fell out of range 
       throw new HttpResponseException(_statusCode); 
      } 
     } 

     return false; 
    } 
} 

现在你需要的属性映射进行注册:

 var constraintResolver = new DefaultInlineConstraintResolver(); 
     constraintResolver.ConstraintMap.Add("rangeWithStatus", typeof(RangeWithStatusRouteConstraint)); 
     config.MapHttpAttributeRoutes(constraintResolver); 

,然后选择路线现在可以是这样的:

public class MyController : ApiController 
{ 
    [Route("Number/{id:int:rangeWithStatus(2, 10, PreconditionFailed)}")] 
    public HttpResponseMessage GetNumber([FromUri] int id) 
    { 
     return Request.CreateResponse(HttpStatusCode.OK, id); 
    } 
} 
在这种情况下 Conflict

是一个字符串表示HttpStatusCode.Conflict枚举,稍后将其转换为约束中的枚举值。

通过这样的设置,如果该值超出[2,10]范围,则​​Web API基础结构将响应409状态代码而不是默认的404值。

1

我认为正确的解决方案是检查控制器内部的约束(如@aanund建议)。但是,如果要在代码中保留Route约束并避免使用条件,则可以使用相同的路由创建另一个操作控制器,但不受限制。如果约束未被验证,新的动作控制器将被调用:

[Route("Number/{id:int:min(2):max(10)}")] 
public HttpResponseMessage GetNumber([FromUri] int id) 
{ 
    Request.CreateResponse(HttpStatusCode.OK, id) 
} 

[Route("Number/{id}")] 
public HttpResponseMessage GetNumber2([FromUri] int id) 
{ 
    Request.CreateResponse(HttpStatusCode.PreconditionFailed); 
} 
5

删除路由约束,并在方法内部进行验证。

约束条件用于确定是否应该使用路由,但是如果输入落在某些参数之外,您希望使用路由命中但更改状态码。

[Route("Number/{id})] // No constraints 
public HttpResponseMessage GetNumber([FromUri] int id) 
{ 
    return (id > 1 && id < 11) // here you validate id range 
     ? Request.CreateResponse(HttpStatusCode.OK, id) 
     : Request.CreateResponse(HttpStatusCode.PreconditionFailed); 
}