I have a set of classes inheriting the the same base class. Each of the concrete classes have an own class for the validation. Another class has a collection of the base class and I want to validate each element with the concrete validator.
Crawling the web I found a question on the FluentValidation GitHub issue tracker. The solution was to use ChildValidatorAdaptor. Unfortunatly they changed the class, so that it uses a generic approach. With this change also PropertyValue is no longer available on the IValidationContext, which would have allowed to retrieve the current type of each entry.
Thought about to solve it with *.SetValidator(new ...).When(...) or ChildRules. But from my understanding both ways will not help me in this situation.
Any hint what is required to achieve this kind of validation behavior with version 11?
public abstract class Base { ... }
public class A : Base {}
public class AValidator : AbstractValidator<A> { ... }
public class B : Base {}
public class BValidator : AbstractValidator<B> { ... }
public class SomeOther
{
List<Base> Elements { get; set; } = new List<Base>();
}
public class SomeOtherValidator : AbstractValidator<SomeOther>
{
public SomeOtherValidator()
{
// use AValidator or BValidator dependend on the concrete type of each element
RuleForEach(x => x.Elements).SetValidator(??);
}
}
FluentValidation docs on Inheritance Validation has this example:
public class ContactRequestValidator : AbstractValidator<ContactRequest>
{
public ContactRequestValidator()
{
RuleForEach(x => x.Contacts).SetInheritanceValidator(v =>
{
v.Add<Organisation>(new OrganisationValidator());
v.Add<Person>(new PersonValidator());
});
}
}
for classes Person
and Organisation
implementing a common IContact
interface.
According to the docs, this should be working for abstract base classes, too:
As of FluentValidation 9.2, if your object contains a property which is a base class or interface, you can set up specific child validators for individual subclasses/implementors.
Which adapted to your case would be
public class SomeOtherValidator : AbstractValidator<SomeOther>
{
public SomeOtherValidator()
{
// use AValidator or BValidator dependend on the concrete type of each element
RuleForEach(x => x.Elements).SetInheritanceValidator(v =>
{
v.Add<A>(new AValidator());
v.Add<B>(new BValidator());
});
}
}
At least that's how I read that document.