如何自定义 ASP.Net 核心模型绑定错误?

How do I customize ASP.Net Core model binding errors?

我想 return 仅标准化来自我的 Web API(Asp.net Core 2.1)的错误响应,但我似乎无法弄清楚如何处理模型绑定错误。

项目刚刚从 "ASP.NET Core Web Application" > "API" 模板创建。我有一个简单的动作定义为:

[Route("[controller]")]
[ApiController]
public class MyTestController : ControllerBase
{
    [HttpGet("{id}")]
    public ActionResult<TestModel> Get(Guid id)
    {
        return new TestModel() { Greeting = "Hello World!" };
    }
}

public class TestModel
{
    public string Greeting { get; set; }
}

如果我使用无效的 Guid(例如,https://localhost:44303/MyTest/asdf)向此操作发出请求,我会收到以下响应:

{
    "id": [
        "The value 'asdf' is not valid."
    ]
}

我在Startup.Configure中得到了以下代码:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    JsonErrorMiddleware.CreateSingleton(env);

    if (!env.IsDevelopment())
    {
        app.UseHsts();
    }

    app
        .UseHttpsRedirection()
        .UseStatusCodePages(async ctx => { await JsonErrorMiddleware.Instance.Invoke(ctx.HttpContext); })
        .UseExceptionHandler(new ExceptionHandlerOptions() { ExceptionHandler = JsonErrorMiddleware.Instance.Invoke })
        .UseMvc()
}

JsonErrorMiddleware 只是一个 class,它将错误转换为我想要 return 的正确形状,并将它们放入响应中。它根本不会因模型绑定错误而被调用(没有 Exception 被抛出并且 UseStatusCodePages 没有被调用)。

我如何连接到模型绑定中以在我的项目中的所有操作中提供标准化的错误响应?

我读了很多文章,但它们似乎都在讨论全局异常处理或验证错误。

值得一提的是,ASP.NET Core 2.1 添加了 [ApiController] 属性,除其他外,该属性通过 returning a BadRequestObjectResultModelState 传入。换句话说,如果你用那个属性装饰你的控制器,你就不再需要做 if (!ModelState.IsValid) 检查。

此外,该功能也是可扩展的。在Startup中,您可以添加:

services.Configure<ApiBehaviorOptions>(o =>
{
    o.InvalidModelStateResponseFactory = actionContext =>
        new BadRequestObjectResult(actionContext.ModelState);
});

以上是默认情况下已经发生的情况,但您可以 customize the lambda that InvalidModelStateResponseFactory is set to 以便 return 随心所欲。