使用父模型值进行子模型validation。 流利的validation。 MVC4

以下是我的问题的简化版本。

我不能压扁模型。 我需要一个“孩子”列表来validation生日。

我似乎无法在Parent类中引用日期,并想知道如何在Fluentvalidation中完成此操作?

模型

[Validator(typeof(ParentValidator))] public class Parent { public string Name { get; set; } public DateTime Birthdate { get; set; } public List Children { get; set; } } public class Child { public string ChildProperty{ get; set; } public DateTime Birthdate { get; set; } } 

validation器

 public class ParentValidator : AbstractValidator { public ParentValidator() { RuleFor(model => model.Name).NotEmpty(); RuleForEach(model => model.Children).SetValidator(new ChildValidator()); } } public class ChildValidator : AbstractValidator { public ChildValidator() { RuleFor(model => model.ChildProperty).NotEmpty(); //Compare birthday to make sure date is < Parents birthday } } 

像这样创建一个自定义属性validation器

 public class AllChildBirtdaysMustBeLaterThanParent : PropertyValidator { public AllChildBirtdaysMustBeLaterThanParent() : base("Property {PropertyName} contains children born before their parent!") { } protected override bool IsValid(PropertyValidatorContext context) { var parent = context.ParentContext.InstanceToValidate as Parent; var list = context.PropertyValue as IList; if (list != null) { return ! (list.Any(c => parent.BirthDay > c.BirthDay)); } return true; } } 

添加这样的规则

 public class ParentValidator : AbstractValidator { public ParentValidator() { RuleFor(model => model.Name).NotEmpty(); RuleFor(model => model.Children) .SetValidator(new AllChildBirtdaysMustBeLaterThanParent()); // Collection validator RuleFor(model => model.Children).SetCollectionValidator(new ChildValidator()); } } 

Custom Propertyvalidation器的替代方法是使用Custom方法:

  public ParentValidator() { RuleFor(model => model.Name).NotEmpty(); RuleFor(model => model.Children).SetCollectionValidator(new ChildValidator()); Custom(parent => { if (parent.Children == null) return null; return parent.Children.Any(c => parent.BirthDay > c.BirthDay) ? new ValidationFailure("Children", "Child cannot be older than parent.") : null; }); } 

显示失败的指标的粗略方式:(应该是其他标识符的名称)

 public class ParentValidator : AbstractValidator { public ParentValidator() { RuleFor(m => m.Children).SetCollectionValidator(new ChildValidator()); Custom(parent => { if (parent.Children == null) return null; var failIdx = parent.Children.Where(c => parent.BirthDay > c.BirthDay).Select(c => parent.Children.IndexOf(c)); var failList = string.Join(",", failIdx); return failIdx.Count() > 0 ? new ValidationFailure("Children", "Child cannot be older than parent. Fail on indicies " + failList) : null; }); } } 

使用set child validator有一种更简单的方法:

 public class ChildValidator : AbstractValidator { public ChildValidator(Parent parent) { RuleFor(model => model.ChildProperty).NotEmpty(); RuleFor(model => model.Birthday).Must(birthday => parent.Birthday > birthday); } } public class ParentValidator : AbstractValidator { public ParentValidator() { RuleFor(model => model.Name).NotEmpty(); } public override ValidationResult Validate(Parent parent) { RuleFor(model => model.Children).SetCollectionValidator(new ChildValidator(this)); return base.Validate(); } } 

现在,通过使用SetCollectionValidator扩展方法并将父对象传递给子validation器,可以进一步简化@ johnny-5的答案 :

 public class ParentValidator : AbstractValidator { public ParentValidator() { RuleFor(model => model.Name).NotEmpty(); RuleFor(model => model.Children) .SetCollectionValidator(model => new ChildValidator(model)) } } public class ChildValidator : AbstractValidator { public ChildValidator(Parent parent) { RuleFor(model => model.ChildProperty).NotEmpty(); RuleFor(model => model.Birthday).Must(birthday => parent.Birthday < birthday); } }