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

时间:2014-10-02 08:12:44

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

我正在使用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 个答案:

答案 0 :(得分: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进行响应。

答案 1 :(得分: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);
}

答案 2 :(得分: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);
}