如何在 UseExceptionHandler 中访问 ModelState

How to access ModelState in UseExceptionHandler

我有域服务,可以为业务验证抛出自定义 DomainServiceValidationException。我想在 ModelState 中全局捕获异常和 return。我目前的工作解决方案是使用 ExceptionFilterAttribute

public class ExceptionHandlerAttribute : ExceptionFilterAttribute
{
    private readonly ILogger<ExceptionHandlerAttribute> _logger;

    public ExceptionHandlerAttribute(ILogger<ExceptionHandlerAttribute> logger)
    {
        _logger = logger;
    }
    public override void OnException(ExceptionContext context)
    {
        
        if (context == null || context.ExceptionHandled)
        {
            return;
        }

       if(context.Exception is DomainServiceValidationException)  
       {
          context.ModelState.AddModelError("Errors", context.Exception.Message);
          context.HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest;
          context.Result = new BadRequestObjectResult(context.ModelState);
       }
       else
       {
            handle exception
       }
    }

}

想知道UseExceptionHandler中间件有没有办法访问ModelState

public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApplicationLifetime appLifetime)
{            
        app.UseExceptionHandler(new ExceptionHandlerOptions()
        {
            ExceptionHandler = async (context) =>
            {
                var ex = context.Features.Get<IExceptionHandlerFeature>().Error;

               // how to access to ModelState here                        
                
            }
        });                
    }            
}

缩短答案:

不,您不能在 UseExceptionHandler 中间件中访问 ModelState。

解释:

首先你要知道ModelState只有在Model Binding后才可用

然后模型绑定在 Action Filters 之前和 Resource Filters 之后调用(见图 1)。但是 Middleware 在过滤器之前调用(见图 2)。

图一:

图二:

参考:

How Filters work

结论:

也就是说,你无法获取UseExceptionHandler中间件中的ModelState

解决方法:

您只能将 ModelState 自动存储在过滤器(Action Filters 或 Exception Filters 或 Result Filters)中,然后您可以在中间件中使用它。

app.UseExceptionHandler(new ExceptionHandlerOptions()
{
    ExceptionHandler = async (context) =>
    {
        var ex = context.Features.Get<IExceptionHandlerFeature>().Error;
        // how to access to ModelState here                        
        var data = context.Features.Get<ModelStateFeature>()?.ModelState;
    }
});

参考:

How to store ModelState automatically