为所有控制器全局验证ModelState.IsValid

Sam*_*Sam 8 c# asp.net-core

在我的ASP.NET核心控制器中,我总是检查ModelState是否有效:

[HttpPost("[action]")]
public async Task<IActionResult> DoStuff([FromBody]DoStuffRequest request)
{
  if (!ModelState.IsValid)
  {
    return BadRequest("invalid parameters");
  }
  else
  {
    return Ok("some data"));
  }
}
Run Code Online (Sandbox Code Playgroud)

有没有办法使用过滤器全局检查ModelState的有效性,所以我不必再次在每个控制器的每个API项目中执行此操作?如果动作可以依赖于模型状态是有效的而不需要检查,那将是很好的:

[HttpPost("[action]")]
public async Task<IActionResult> DoStuff([FromBody]DoStuffRequest request)
{
  return Ok("some data"));
}
Run Code Online (Sandbox Code Playgroud)

smo*_*nes 8

你可以使用ActionFilter.它不是全局的,但它将问题从您的方法体转移到属性中.我意识到它并没有完全解决你的问题,但它可能比什么都没有好.

public class ModelStateValidationActionFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        var modelState = actionContext.ModelState;

        if (!modelState.IsValid)
            actionContext.Response = actionContext.Request
                 .CreateErrorResponse(HttpStatusCode.BadRequest, modelState);
    }
}
Run Code Online (Sandbox Code Playgroud)

在你的控制器中:

[HttpPost]
[ModelStateValidationActionFilter]
public IHttpActionResult Post(object model)
{

}
Run Code Online (Sandbox Code Playgroud)

我相信你也可以在你的控制器上设置它.我实际上没有尝试过,但据此,它可以工作.

[ModelStateValidationActionFilter]
public class MyApiController : ApiController
{

}
Run Code Online (Sandbox Code Playgroud)

编辑:

正如@Camilo Terevinto所说,Core有点不同.ActionFilter如果你想使用Core,只需使用它.

public class ModelStateValidationActionFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext context)
    {    
        var modelState = context.ModelState;

        if (!modelState.IsValid)
            context.Result = new ContentResult()
            {
                Content = "Modelstate not valid",
                StatusCode = 400
            };
        base.OnActionExecuting(context);
    }
}
Run Code Online (Sandbox Code Playgroud)


SO *_*ood 8

到目前为止,现有的答案是ASP.NET Web API而不是ASP.NET Core.在ASP.NET Core中实际执行此操作的方法是:

public class SampleActionFilter : IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // do something before the action executes
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // do something after the action executes
    }
}
Run Code Online (Sandbox Code Playgroud)

并且您可以在Startup.cs中全局注册此过滤器,因此这将在每次调用中执行,您不必在每个操作/控制器中重复它:

options.Filters.Add(typeof(SampleActionFilter));
Run Code Online (Sandbox Code Playgroud)

请参阅官方文档中的更多内容.


Jas*_* La 7

后续操作:在ASP.NET Core 2.1中,有一个名为的控制器属性[ApiController]。如果包含该属性,它将自动使用一个ActionFilter名为的内置ModelStateInvalidFilter函数,这意味着将永远无法访问检查ModelState的任何自定义操作过滤器,因为该[ApiController]属性已经注册了自己的过滤器。

为了抑制此行为,当前文档提供了以下选项:

services.Configure<ApiBehaviorOptions>(options =>
{
   options.SuppressModelStateInvalidFilter = true; // This is the setting
});
Run Code Online (Sandbox Code Playgroud)


Mer*_*aya 5

对于 ASP.NET Core 2.0,避免对所有ControllersActions单独应用属性;

定义过滤器:

namespace Test
{
    public sealed class ModelStateCheckFilter : IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context) { }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            if (!context.ModelState.IsValid)
            {
                context.Result = new BadRequestObjectResult(context.ModelState);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在您的 中Startup.cs,将其添加为过滤器:

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc(config =>
        {
            config.Filters.Add(new ModelStateCheckFilter());
        });
    }
Run Code Online (Sandbox Code Playgroud)