FluentValidation 集合属性未验证

FluentValidation collection properties not validated

这是我第一次尝试实现 FluentValidation,因为我需要涵盖复杂的验证场景。

我正在尝试验证的 class 具有大量属性、复杂对象和多个集合。

我在验证主属性 class 甚至检查集合是否不为空时都没有遇到麻烦,但是在验证每个集合中的对象属性时我确实遇到了问题。

为了实现这一点,我遵循了此处记录的示例(在 "Re-using Validators for Collections" 下查看): http://fluentvalidation.codeplex.com/wikipage?title=creatingavalidator

这些是我的模型 classes(减少以提高可读性)

public class Caso
{
public int Id { get; set; } 
public string Descripcion { get; set; }
public List<Medicamento> Medicamentos { get; set; }
}

public class Medicamento
{
public int Id { get; set; }
public string Nombre { get; set; }
}

这些是验证器 classes:

public class CasoValidator : AbstractValidator<CasoAdverso>
{
    public CasoValidator()
    {
        RuleSet("Iniciar", () =>
        {
            // Validated OK
            RuleFor(x => x.Descripcion).NotEmpty();
            // Validated OK
            RuleFor(x => x.Medicamentos).Must(x => x != null && x.Count > 0).WithMessage("No puede iniciar un caso sin medicamentos cargados");
            RuleFor(x => x.Medicamentos).SetCollectionValidator(new MedicamentoValidator());
        });
    }
}

public class MedicamentoValidator : AbstractValidator<Medicamento>
{
    public MedicamentoValidator()
    {
        // NOT Validated. Even if the object property is empty the error message doesn't appear. I also checked using "NotNull" and "NotEmpty" clauses
        RuleFor(x => x.Nombre).NotNull().WithMessage("Debe especificar un nombre"); 
    }
}

(注意:我使用 RuleSet 是因为不同的验证模式取决于工作流中的文档状态)

我正在从控制器手动执行验证(没有 MVC 集成)

[HttpPost]
public ActionResult Iniciar(Caso c)
{
    CasoValidator validator = new CasoValidator();
    FluentValidation.Results.ValidationResult validate = validator.Validate(c, ruleSet: "Iniciar"); 


    // ...
}

通过此实现,主要 class 的属性得到了很好的验证,但我还需要验证集合中 "Medicamento" class 的每个 属性。

我能在这里遗漏什么吗?。是否应使用可用的 RuleForEach 子句对其进行验证?

我们将不胜感激。

RuleSet 设置似乎适用于子验证器和主要验证器。

我在 xUnit.net 测试中测试了您的代码,并确认了它。

如果您更改要执行的规则集,您应该会发现它按预期工作:

CasoValidator validator = new CasoValidator();
FluentValidation.Results.ValidationResult validate = validator.Validate(c, ruleSet: "default,Iniciar");

'default' 规则集将适用于 MedicamentoValidator 规则。

我没有在文档中找到这个,只能通过测试找到。

这是示例单元测试:

[Fact]
public void Test1()
{

    Caso c = new Caso()
    {
        Id = 1,
        Descripcion = "none",
        Medicamentos = new List<Medicamento>()
    };

    c.Medicamentos.Add(new Medicamento()
    {
        Id = 0,
        Nombre= null
    });

    CasoValidator validator = new CasoValidator();
    FluentValidation.Results.ValidationResult validate = validator.Validate(c, ruleSet: "default,Iniciar");

    Assert.NotEmpty(validate.Errors);
}

更新:我找到了 Jeremy Skinner 对这种行为的参考: http://fluentvalidation.codeplex.com/discussions/266920

Rulesets cascade to any child validators, so whichever ruleset is selected for use by the top-level validator will also be used by the child validator. So if you ran the "Minimal" ruleset on the CreateProfileModelValidator, then only rules in the "Minimal" ruleset will be run on both the CreateProfileModelValidator and the ProfileValidator.

作为补充: 名为 GroupMemberIds 的集合应该有 AdminMemebrId:

RuleFor(r => new { r.GroupMemberIds, r.AdminMemberId }).Must(a => a.GroupMemberIds.Contains(a.AdminMemberId));