ModelState无效时触发InvalidModelStateResponseFactory

Kil*_*ine 7 c# rest fluentvalidation asp.net-core

我正在使用 asp.net core 3.0 编写一个 API,并为所有控制器配置了以下行为的应用程序:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers()
        .ConfigureApiBehaviorOptions(setupAction =>
        {
            setupAction.InvalidModelStateResponseFactory = context =>
            {
                var problemDetails = new ValidationProblemDetails(context.ModelState)
                {
                    Type = "https://courselibrary.com/modelvalidationproblem",
                    Title = "One or more model validation errors occurred.",
                    Status = StatusCodes.Status422UnprocessableEntity,
                    Detail = "See the errors property for details",
                    Instance = context.HttpContext.Request.Path
                };

                problemDetails.Extensions.Add("traceId", context.HttpContext.TraceIdentifier);

                return new UnprocessableEntityObjectResult(problemDetails)
                {
                    ContentTypes = { "application/problem+json" }
                };
            };
        });
    ...
}
Run Code Online (Sandbox Code Playgroud)

[Required]这对于我的输入(例如:)类属性上的数据注释非常有效。如果任何注释失败,它会返回 422 Unprocessable Entity 响应,如下所示:

{
    "type": "https://courselibrary.com/modelvalidationproblem",
    "title": "One or more model validation errors occurred.",
    "status": 422,
    "detail": "See the errors property for details",
    "instance": "/api/songbooks/21924d66-dac6-43a5-beee-206de4d35216/songs",
    "traceId": "0HLQFGSFIFL5L:00000001",
    "errors": {
        "Title": [
            "The Title field is required."
        ]
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,我在控制器中实现 FluentValudation,如下所示:

if (!newSong.IsValid)
{
    newSong.Validate().AddToModelState(ModelState, null);
    _logger.LogWarning("{method} failed model validation (ModelState: {@modelState}), returning Unprocessable Entity", nameof(Post), ModelState.Values.SelectMany(v => v.Errors));
    return UnprocessableEntity(ModelState);                
}
Run Code Online (Sandbox Code Playgroud)

但是,这不会InvalidModelStateResponseFactory像内置验证那样触发。

有谁知道如何从控制器内触发相同类型的事件以使用这个方便的处理程序?

Kil*_*ine 7

事实上,有一个非常简单的答案。通过使用此 ValidationProblem 模式,您可以简单地返回,而不是返回ActionResultofOk()或之类的东西,它将使用Api 配置中设置的工厂!BadRequest()ValidationProblem(ModelState)Startup.cs

所以我可以这样做:

if (!newSong.IsValid)
{
    newSong.Validate().AddToModelState(ModelState, null);
    _logger.LogWarning("{method} failed model validation (ModelState: {@modelState}), returning Unprocessable Entity", nameof(Post), ModelState.Values.SelectMany(v => v.Errors));
    return ValidationProblem(ModelState);                
}
Run Code Online (Sandbox Code Playgroud)

此外,您需要重写该行为以将其从您的启动中拉出,如下所示(感谢 Kevin Dockx 提出这个想法):

public override ActionResult ValidationProblem([ActionResultObjectValue] ModelStateDictionary modelStateDictionary)
    {
        var options = HttpContext.RequestServices.GetRequiredService<IOptions<ApiBehaviorOptions>>();
        return (ActionResult)options.Value.InvalidModelStateResponseFactory(ControllerContext);
    }
Run Code Online (Sandbox Code Playgroud)