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); 
}