如何设置ASP.NET Web Api路由约束HTTP状态返回码

3

我正在使用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?

非常感谢。

3个回答

8

您可以创建一个自定义路由约束,检查您希望的最小值和最大值,并允许您在约束未正确满足的情况下指定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。

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

1
我认为正确的解决方案是在控制器内检查约束条件(正如@aanund所建议的那样)。但是,如果您想保留路由约束并避免在代码中使用条件语句,则可以创建另一个具有相同路由但没有约束条件的操作控制器。如果未验证约束条件,则将调用新的操作控制器:
[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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接