Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fluent Validation - pass parameter to collection validator

I'm using fluent validation i ASP.NET MVC application and I've had a problem. This is my rule:

RuleFor(x => x.SimpleList)
       .SetCollectionValidator(new SimpleListValidator())
       .When(x => x.Type == SimpleEnum.SpecificType);

I want to pass x.Type param to SimpleListValidator, how can I do this? Some kind of extension method? It should looks like:

    RuleFor(x => x.SimpleList)
       .SetCollectionValidator(new SimpleListValidator(x => x.Type))
       .When(x => x.Type == SimpleEnum.SpecificType);
like image 928
Adrian Bystrek Avatar asked Aug 27 '15 10:08

Adrian Bystrek


People also ask

How do you validate fluent validation?

To run the validator, instantiate the validator object and call the Validate method, passing in the object to validate. Customer customer = new Customer(); CustomerValidator validator = new CustomerValidator(); ValidationResult result = validator. Validate(customer);

Is fluent validation good?

FluentValidation provides a great alternative to Data Annotations in order to validate models. It gives better control of validation rules and makes validation rules easy to read, easy to test, and enable great separation of concerns.

How do you debug fluent validation rules?

There is no way to debug Fluent Validator code with Visual Studio tools. You need to comment the specific part of code (RuleFor) that you want to test. Keep doing it until all rules are tested.

Is fluent validation open source?

FluentValidation is an open source validation library for . NET. It supports a fluent API, and leverages lambda expressions to build validation rules.


2 Answers

It is possible and you can do it like this:

RuleFor(x => x.SimpleList)
   .SetCollectionValidator(model => new SimpleListValidator(model))
   .When(x => x.Type == SimpleEnum.SpecificType);

In your SetCollectionValidator class you have to create a constructor accepting your model as a parameter (or anything else you'd like to pass to the validator). Remember though that you should leave a parameter-less constructor in the SimpleListValidator class.

like image 114
Jan W Avatar answered Sep 23 '22 04:09

Jan W


After you set collection validator for property - you can forget about fact, that main model and (n - 1) submodels exists except submodel being currently validated. And there is no way to pass main model as a parameter in SetCollectionValidator.

So you have to use RuleForEach method instead of setting collection validator:

RuleForEach(x => x.SubEntities)
    .Must((model, submodel) => IsValidFirst(submodel, model)) // your rules should go here to be applicable to each collection item
        .WithMessage("The item with values {0}, {1} has duplicates in collection of {2} items",
            (model, submodel) => submodel.Field1,
            (model, submodel) => submodel.Field2,
            (model, submodel) => model.SubEntities.Count); // for error message building you can access both model and submodel being validated
    .Must((model, submodel) => IsValidSecond(submodel, model)) // yet another rule
        .WithMessage("...")
    .When(model => 
        model.Type == SimpleEnum.SpecificType) // can access to main model only, but it is enough for your purposes

I guess that possibility to tell child validator about fact, that parent model could exists, should be implemented in future, but right now there is the only working approach, mentioned above.

UPDATE

You can create custom ModelBinder, that would set Parent property of each subentity to main entity value, and continue using SetCollectionValidator().

like image 5
Evgeny Levin Avatar answered Sep 23 '22 04:09

Evgeny Levin