【问题标题】:Triggering InvalidModelStateResponseFactory when ModelState is invalidModelState 无效时触发 InvalidModelStateResponseFactory
【发布时间】:2019-10-13 02:46:14
【问题描述】:

我正在使用 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" }
                        };
                    };
                });
        ...  
    }

这非常适用于我的输入(例如:[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."
        ]
    }
}

但是,我在我的控制器中实现 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);                
}

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

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

【问题讨论】:

  • 您将无法“触发”它本身,您的控制器的操作方法必须返回UnprocessableEntityObjectResult
  • 是的,我很担心这个。我最终创建了一个静态类,它基本上封装了InvalidModelStateResponseFactory 中的行为,并在两个地方(控制器和Startup.cs)简单地使用它。谢天谢地,我在这两个地方都有 ModelState 和 HttpContext ......如果没有其他人有任何建议,我会发布我最终得到的结果。

标签: c# rest asp.net-core fluentvalidation


【解决方案1】:

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

所以我可以这样做:

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);                
}

此外,您需要像这样覆盖行为以将其从您的启动中移除(感谢 Kevin Dockx 的这个想法):

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

【讨论】:

  • 您能否添加一个完整的示例来说明如何处理 ValidationProblem 的覆盖器?
猜你喜欢
  • 2015-08-09
  • 1970-01-01
  • 2018-04-10
  • 1970-01-01
  • 2017-05-30
  • 2012-03-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多