49

I am trying out FluentValidation on a project that contains complex view models and I read the documentation here but I don't see how to set up the rules to validate a list of objects declared in my view model. In my example below, the list in the view model contains 1 or more Guitar objects. Thanks

View Model

 [FluentValidation.Attributes.Validator(typeof(CustomerViewModelValidator))]
    public class CustomerViewModel
    {
        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        [Display(Name = "Phone")]
        public string Phone { get; set; }

        [Display(Name = "Email")]
        public string EmailAddress { get; set; }

        public List<Guitar> Guitars { get; set; } 
    }

Guitar class used in View Model

public class Guitar
{
    public string Make { get; set; }
    public string Model { get; set; }
    public int? ProductionYear { get; set; }
}

View Model Validator Class

 public class CustomerViewModelValidator : AbstractValidator<CustomerViewModel>
    {


        public CustomerViewModelValidator()
        {
            RuleFor(x => x.FirstName).NotNull();
            RuleFor(x => x.LastName).NotNull();
            RuleFor(x => x.Phone).NotNull();
            RuleFor(x => x.EmailAddress).NotNull();
           //Expects an indexed list of Guitars here????


        }
    }
Slinky
  • 5,662
  • 14
  • 76
  • 130
  • Cant u have separete Validator for Guitar class?. What kind of validation u want on Ilist, is it to have more than one element? – Nitin Varpe Jan 23 '14 at 13:47

5 Answers5

83

This code deprecated: RuleFor(x => x.Guitars).SetCollectionValidator(new GuitarValidator());

This is new:

RuleForEach(x => x.Guitars).SetValidator(new GuitarValidator());
pushkin
  • 9,575
  • 15
  • 51
  • 95
71

You would add this to your CustomerViewModelValidator

RuleFor(x => x.Guitars).SetCollectionValidator(new GuitarValidator());

So your CustomerViewModelValidator would look like this:

public class CustomerViewModelValidator : AbstractValidator<CustomerViewModel>
{
    public CustomerViewModelValidator()
    {
        RuleFor(x => x.FirstName).NotNull();
        RuleFor(x => x.LastName).NotNull();
        RuleFor(x => x.Phone).NotNull();
        RuleFor(x => x.EmailAddress).NotNull();
        RuleFor(x => x.Guitars).SetCollectionValidator(new GuitarValidator());
    }
}

Add the GuitarValidator would look something like:

public class GuitarValidator : AbstractValidator<Guitar>
{
    public GuitarValidator()
    {
        // All your other validation rules for Guitar. eg.
        RuleFor(x => x.Make).NotNull();
    }
 }
Jonathon Choo
  • 804
  • 8
  • 5
  • 34
    SetCollectionValidator has been deprecated, use RuleForEach now. – rfcdejong Oct 19 '18 at 11:54
  • 10
    Syntax for RuleForEach(x => x.Guitars).SetValidator(new GuitarValidator()); ref answer https://stackoverflow.com/a/53227565/193061 – Ram Jan 21 '20 at 07:04
3
RuleForEach(
  itemToValidate => 
     new YourObjectValidator());


public class YourObjectValidator : AbstractValidator<YourObject>
{
  public EdgeAPIAddressValidator()
  {
     RuleFor(r => r.YourProperty)
         .MaximumLenght(100);
  }
}
Nico Campisano
  • 179
  • 1
  • 4
  • 4
    Although this code snippet may answer the question, including an explanation of *why* and *how* it helps solve the problem improves the quality and longevity of your answer, especially regarding older questions like this one. See ["How do I write a good answer?"](https://stackoverflow.com/help/how-to-answer). – slothiful Jul 01 '19 at 15:25
3

You can use childrule

RuleForEach(p => p.Guitars).ChildRules(child =>{
child.RuleFor(x=>x.Make).NotEmpty().WithMessage({PropertyName}required.") .NotNull(); });
Elikill58
  • 4,050
  • 24
  • 23
  • 45
1

It works with the latest version of Fluent and contains a complete example to be used.

The code in the answer it's deprecated.

Nico Campisano
  • 179
  • 1
  • 4