为所有控制器全局validationModelState.IsValid
在我的ASP.NET核心控制器中,我总是检查ModelState是否有效:
[HttpPost("[action]")] public async Task DoStuff([FromBody]DoStuffRequest request) { if (!ModelState.IsValid) { return BadRequest("invalid parameters"); } else { return Ok("some data")); } }
有没有办法使用filter全局检查ModelState的有效性,所以我不必再次在每个控制器的每个API项目中执行此操作? 如果动作可以依赖于模型状态有效而不需要检查,那将是很好的:
[HttpPost("[action]")] public async Task DoStuff([FromBody]DoStuffRequest request) { return Ok("some data")); }
您可以使用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); } }
在你的控制器中:
[HttpPost] [ModelStateValidationActionFilter] public IHttpActionResult Post(object model) { }
我相信你也可以在你的控制器上设置它。 我实际上没有尝试过,但据此,它可以工作。
[ModelStateValidationActionFilter] public class MyApiController : ApiController { }
编辑:
正如@Camilo Terevinto所说,Core有点不同。 如果你想使用Core,只需使用这个ActionFilter
即可。
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); } }
到目前为止,现有的答案是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 } }
并且您可以在Startup.cs中全局注册此filter,因此这将在每次调用中执行,您不必在每个操作/控制器中重复它:
options.Filters.Add(typeof(SampleActionFilter));
请参阅官方文档中的更多内容 。
对于ASP.NET Core 2.0,避免将属性单独应用于所有Controllers
或Actions
;
定义filter:
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); } } } }
然后在Startup.cs
,将其添加为filter:
public void ConfigureServices(IServiceCollection services) { services.AddMvc(config => { config.Filters.Add(new ModelStateCheckFilter()); }); }
作为后续内容:在ASP.NET Core 2.1中,有一个名为[ApiController]
的控制器属性。 如果包含该属性,它会自动使用名为ModelStateInvalidFilter
的内置ActionFilter
,这意味着永远不会到达任何检查ModelState的自定义操作filter,因为[ApiController]
属性已经注册了自己的filter。
要禁止该行为,当前文档提供此选项:
services.Configure(options => { options.SuppressModelStateInvalidFilter = true; // This is the setting });
使用HandleInvalidModelState
PM> Install-Package HandleInvalidModelState
例
[HttpPost] [TypeFilter(typeof(HandleInvalidModelWithViewActionFilterAttribute))] public IHttpActionResult Post(object model) {}
除了基本情况场景(返回带有无效模型的视图)包之外,还支持返回请求的Json和重定向 。
免责声明:该软件包的作者
对于async
方法,filter必须实现IAsyncActionFilter
。 我把这个filter放在一起,其中:
- 如果ModelState有效,则不执行任何操作
要么
- 将Result设置为BadRequestObjectResult,并提供有关失败的详细信息
- 使用更多详细信息记录ModelState
public class ValidModelStateAsyncActionFilter : IAsyncActionFilter { // https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/loggermessage?view=aspnetcore-2.1 private static readonly Action, Exception> ModelStateLoggerAction; private readonly ILogger logger; static ValidModelStateAsyncActionFilter() { ModelStateLoggerAction = LoggerMessage.Define>(LogLevel.Warning, new EventId(1, nameof(ValidModelStateAsyncActionFilter)), "{ModelState}"); } public ValidModelStateAsyncActionFilter(ILogger logger) { this.logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next) { if (context.ModelState.IsValid) await next(); this.LogModelState(context); context.Result = new BadRequestObjectResult(GetErrorResponse(context)); } private static ErrorResponse GetErrorResponse(ActionContext context) { return new ErrorResponse { ErrorType = ErrorTypeEnum.ValidationError, Message = "The input parematers are invalid.", Errors = context.ModelState.Values.SelectMany(x => x.Errors) .Select(x => x.ErrorMessage) .Where(x => !string.IsNullOrEmpty(x)) .ToList() }; } private void LogModelState(ActionContext context) { // credit: https://blogs.msdn.microsoft.com/mazhou/2017/05/26/c-7-series-part-1-value-tuples/ var items = from ms in context.ModelState where ms.Value.Errors.Any() let fieldKey = ms.Key let errors = ms.Value.Errors from error in errors select (Key: fieldKey, ErrorMessage: error.ErrorMessage, ExceptionMessage: error.Exception.Message); ModelStateLoggerAction(this.logger, items.ToList(), null); } }
- vNextdependency injection通用接口
- ASP.NET Core MetaDataType属性不起作用
- NLog没有写入事件日志.NET Core 2.1
- 绕过.net核心中的无效SSL证书
- ASP.NET Core UseSetting来自集成测试
- 在DbContext.OnConfiguring和AspCore Startup.ConfigureServices中定义optionsBuilder时,预期的结果是什么?
- 工厂模式与开放的generics
- .NET Core从appsettings.json获取连接字符串
- .Net MVC 4项目因事件日志错误而失败“模块DLL C:\ WINDOWS \ system32 \ inetsrv \ aspnetcore.dll无法加载。 数据是错误的。”