当模型的 FluentValidation 在 ASP.Net Core 中无效时,为什么我的控制器会受到影响?

问题描述 投票:0回答:2

我相信我正在按照文档做所有事情。我在 Startup.cs 类中设置了流畅的验证:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSwaggerGen(swagger =>
    {
        swagger.SwaggerDoc("v1", new OpenApiInfo { Title = _swaggerApiName });
        swagger.DescribeAllParametersInCamelCase();
    });

    services.AddMvcCore()
        .AddJsonOptions(options =>
        {
            options.JsonSerializerOptions.IgnoreNullValues = false;
        })
        .AddFluentValidation(options =>
        {                    
            options.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
            options.RegisterValidatorsFromAssemblyContaining(typeof(ContentCoreMarker));
            options.ImplicitlyValidateChildProperties = true;
        })
       .AddApiExplorer()
       .AddRazorViewEngine();
}

我的简单验证器。请注意,RuleFor 上遇到了断点。

public class AddSectionRequestValidator : AbstractValidator<AddSectionRequest>
{
    public AddSectionRequestValidator()
    {
        RuleFor(m => m.SectionName)
            .NotEmpty()
            .MinimumLength(1)
            .WithMessage("invalid");

        RuleFor(m => m.ParentSectionId)
            .NotEmpty();
    }
}

fluidvalidation 不应该在不点击控制器操作的情况下自动返回验证错误吗?

根据文档

如果您想禁用此行为,以便 FluentValidation 成为唯一执行的验证库,您可以在应用程序启动例程中将 RunDefaultMvcValidationAfterFluentValidationExecutes 设置为 false

控制器中的断点仍然被命中。我还创建了验证器的本地副本进行测试,结果是模型无效。

[HttpPost]
public async Task<IActionResult> Post([FromBody]AddSectionRequest request)
{
    var validator = new AddSectionRequestValidator();
    var isValid = validator.Validate(request); // Not valid

    var result = await _addSectionRequestHandler.Handle(request);
    return Ok(result.NewSectionId);
}

我使用的是 ASP.Net Core 3.1

asp.net-core fluentvalidation
2个回答
3
投票

终于发现问题了。我的问题是我缺少控制器顶部的 [ApiController] 属性:

    [ApiController] // <-- Fix is here
    [Route("[controller]")]
    public class SectionController : ControllerBase
    {

        [HttpPost]
        public async Task<IActionResult> Post([FromBody] DtoArticle request)
        {
            var ms = ModelState;
            if (!ms.IsValid)
                throw new Exception("Should not be possible");

            return Ok();
        }
    }

我的控制器不再被击中,而是从邮递员那里得到了整洁的回复:

{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "|f5f5b1a2-4dd202e6998784c3.",
    "errors": {
        "Name": [
            "'Name' is required."
        ],
        "Content": [
            "'Content' is required."
        ]
    }
}

-1
投票

你的控制器被击中,因为那是你应该处理验证的地方。 文档有一个在控制器中使用验证器的示例:

配置 FluentValidation 后,ASP.NET 将使用启动例程中配置的验证器映射自动验证传入请求。

[HttpPost]
public IActionResult Create(Person person) {

    if(!ModelState.IsValid) { // re-render the view when validation failed.
        return View("Create", person);
    }

    Save(person); //Save the person to the database, or some other logic

    TempData["notice"] = "Person successfully created";
    return RedirectToAction("Index");

}

如您所见,他们检查

ModelState
是否有效,然后返回带有
Person
模型的视图。

由于您没有返回视图,我建议您尝试返回 ModelState:

[HttpPost]
public async Task<IActionResult> Post([FromBody]AddSectionRequest request)
{
    if(!ModelState.IsValid) return BadRequest(ModelState);

    var result = await _addSectionRequestHandler.Handle(request);
    return Ok(result.NewSectionId);
}

这将返回一个像这样的 json:

{
  "Name": ["The Name field is required."]
}

我还发现了这篇blogpost,它更详细地介绍了模型验证并封装了模型验证,以便为每个控制器操作启用它。

© www.soinside.com 2019 - 2024. All rights reserved.