【问题标题】:How to set ASP.NET Web Api Route Constraint HTTP Status Return Code如何设置 ASP.NET Web Api 路由约束 HTTP 状态返回码
【发布时间】:2014-10-02 08:12:43
【问题描述】:

我正在使用 ASP.NET Web Api 2 框架并使用如下基本路由约束。

    [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 何时与上述约束冲突,例如1 或 11, 如何覆盖默认的 HTTP 状态返回码 404?

非常感谢。

【问题讨论】:

    标签: asp.net-web-api asp.net-web-api2 asp.net-web-api-routing


    【解决方案1】:

    您可以创建自定义路由约束来检查您希望的最小值、最大值,此外还允许您指定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);
        }
    }
    

    在这种情况下,ConflictHttpStatusCode.Conflict 枚举的字符串表示形式,稍后将其转换为约束中的枚举值。

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

    【讨论】:

      【解决方案2】:

      去掉路由的约束,在方法内部做验证。

      约束用于确定是否应该使用路由,但您希望使用要命中的路由,但如果输入超出某些参数,则更改状态代码。

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

      【讨论】:

        【解决方案3】:

        我认为正确的解决方案是检查控制器内部的约束(如@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);
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-12-04
          • 1970-01-01
          • 1970-01-01
          • 2022-02-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-11
          相关资源
          最近更新 更多