验证查询字符串参数时,MVC控制器应返回400

时间:2018-02-22 20:54:03

标签: asp.net-mvc asp.net-mvc-routing bad-request

假设你在MVC控制器中有一个简单的方法......

HTTP GET http://my-server/api/12321312?includeNonActive=thisIsNotABooleanValue

如果将无效值(非布尔值)传递给Boolean.TryParse()查询字符串参数,有没有办法让MVC自动返回HTTP 400?

return BadRequest("wtf")

当然,我可以接受'includeNonActive'的字符串类型,使用bind 127.0.0.1 192.168.20.37 port 6379 dir .bind 127.0.0.1 192.168.20.140 port 16379 sentinel monitor redis-cluster 192.168.20.37 6379 2 ,但这在Swagger中看起来很难看。

2 个答案:

答案 0 :(得分:1)

  

如果将无效值(非布尔值)传递给'includeNonActive'查询字符串参数,有没有办法让MVC自动返回HTTP 400?

当然,您可以为此构建一个动作过滤器。

notification

然后使用过滤器:

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class EnsureBooleanQueryParameterAttribute : ActionFilterAttribute
{
    public EnsureBooleanQueryParameterAttribute(string parameterName)
    {
        if (string.IsNullOrEmpty(parameterName))
            throw new ArgumentException($"'{nameof(parameterName)}' is required.");
        this.ParameterName = parameterName;
    }

    public string ParameterName { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var attribute = (EnsureBooleanQueryParameterAttribute)filterContext.ActionDescriptor
            .GetCustomAttributes(typeof(EnsureBooleanQueryParameterAttribute), true)
            .FirstOrDefault();

        // The attribute exists on the current action method
        if (attribute != null)
        {
            string param = filterContext.HttpContext.Request.QueryString[attribute.ParameterName];
            bool result;
            // If the query string value is present and not boolean
            if (!string.IsNullOrEmpty(param) && !bool.TryParse(param, out result))
            {
                filterContext.Result = new HttpStatusCodeResult(400, 
                    "Invalid boolean query string value for '{attribute.ParameterName}'.");
            }
        }
    }
}

您可以将此作为起点,添加可用于指定数据类型的[Route("{id}", Name = "GetById")] [HttpGet] [ProducesResponseType(typeof(SomeType), (int)HttpStatusCode.OK)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.Unauthorized)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.Forbidden)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.BadRequest)] [ProducesResponseType(typeof(string), (int)HttpStatusCode.ServiceUnavailable)] [EnsureBooleanQueryParameter("includeNonActive")] public async Task<IActionResult> Get(string id, bool? includeNonActive = false) { // some stuff } 参数和Enum参数,以指示该值是否必须存在于URL。

答案 1 :(得分:0)

我没有说明我使用的是MVC Core,因此我必须更改一些内容才能让它适合我。这是我的版本。

[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
public class BooleanQueryStringParameterTypeValidatorAttribute : ActionFilterAttribute
{
    public BooleanQueryStringParameterTypeValidatorAttribute(string parameterName)
    {
        if(string.IsNullOrWhiteSpace(parameterName))
            throw new ArgumentException($"'{nameof(parameterName)}' is required.");
        this.ParameterName = parameterName;
    }

    protected string ParameterName { get; set; }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if(!filterContext.HttpContext.Request.QueryString.HasValue)
            return;

        ControllerActionDescriptor actionDescriptor = filterContext.ActionDescriptor as ControllerActionDescriptor;
        var attribute = actionDescriptor.MethodInfo.GetCustomAttributes(typeof(BooleanQueryStringParameterTypeValidatorAttribute), true).FirstOrDefault() as BooleanQueryStringParameterTypeValidatorAttribute;

        // The attribute exists on the current action method
        if(attribute != null)
        {
            Dictionary<string, StringValues> queryString = QueryHelpers.ParseNullableQuery(filterContext.HttpContext.Request.QueryString.Value);
            if(queryString != null && queryString.ContainsKey(attribute.ParameterName))
            {
                bool result;
                // If the query string value is present and not boolean
                if(!string.IsNullOrEmpty(queryString[attribute.ParameterName]) && !bool.TryParse(queryString[attribute.ParameterName], out result))
                {
                    filterContext.Result = new BadRequestObjectResult($"Invalid boolean query string value for '{attribute.ParameterName}'.");
                }
            }
        }
    }
}