MVC 控制器在验证查询字符串参数时应该 return 400
MVC controller should return 400 when validation query string parameters
假设您在 MVC 控制器中有一个简单的方法...
[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)]
public async Task<IActionResult> Get(string id, bool? includeNonActive = false)
{
// some stuff
}
如果向 includeNonActive
查询字符串参数传递了无效值(非布尔值),是否有任何方法可以让 MVC 自动 return HTTP 400?
HTTP GET http://my-server/api/12321312?includeNonActive=thisIsNotABooleanValue
当然,我可以接受 'includeNonActive' 的字符串类型,使用 Boolean.TryParse()
和 return BadRequest("wtf")
,但这在 Swagger 中看起来很难看。
Is there any way to get MVC to automagically return a HTTP 400 if invalid value (non-boolean) are passed to the 'includeNonActive' query string parameter?
当然,您可以为此构建一个操作过滤器。
[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
参数和用于指示值是否必须存在的 bool
参数在 URL.
我没有指定我使用的是 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}'.");
}
}
}
}
}
假设您在 MVC 控制器中有一个简单的方法...
[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)]
public async Task<IActionResult> Get(string id, bool? includeNonActive = false)
{
// some stuff
}
如果向 includeNonActive
查询字符串参数传递了无效值(非布尔值),是否有任何方法可以让 MVC 自动 return HTTP 400?
HTTP GET http://my-server/api/12321312?includeNonActive=thisIsNotABooleanValue
当然,我可以接受 'includeNonActive' 的字符串类型,使用 Boolean.TryParse()
和 return BadRequest("wtf")
,但这在 Swagger 中看起来很难看。
Is there any way to get MVC to automagically return a HTTP 400 if invalid value (non-boolean) are passed to the 'includeNonActive' query string parameter?
当然,您可以为此构建一个操作过滤器。
[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
参数和用于指示值是否必须存在的 bool
参数在 URL.
我没有指定我使用的是 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}'.");
}
}
}
}
}