New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RuleForEach.SetValidator does not support AbstractValidator<T> #1080
Comments
Hi, There are 3 overloads of
What error are you seeing? |
My bad - It was a problem with generics. It seems you can't run a validator on an interface. Is there some way to achieve what I'm trying to do? The error is
|
That's correct - the compiler won't allow that as the types don't match. Either your proprety would need to be defined as (Just a tip, github uses 3 backticks to format code blocks: https://help.github.com/en/articles/creating-and-highlighting-code-blocks) |
That's a shame... as I need to validate against different types of IContact (Email, Phone, Skype etc.) If I make the EDIT Ignore the above - how can I validate my implementations when the properties don't exist on the interface? i.e.
I'm not saying this "should" work. I'd like to know if it's possible to cast the (You saw me struggling with the code formatting - thanks for the tip!) |
Just to explain further, validators are contravariant in T (the interface is defined a So as this can't be handled at a compiler level it must be done at runtime. You need to be making a decision at runtime to select which validator you want to use based on the type of each element in the collection. There's a few ways to do this: Use OfType in your rule definition
This is simple, but is expensive as method calls inside Implement a Polymorphic child validatorEdit: This is now available in FluentValidation 9.2. Please see here: https://docs.fluentvalidation.net/en/latest/inheritance.htmlYou can create a custom property validator that inspects the type of the current item being validated and picks the appropriate validator to use. The property validator would be defined like this: public class PolymorphicValidator<TInterface> : ChildValidatorAdaptor {
Dictionary<Type, IValidator> _derivedValidators = new Dictionary<Type, IValidator>();
// Need the base constructor call, even though we're just passing null.
public PolymorphicValidator() : base((IValidator)null, typeof(IValidator<TInterface>)) {
}
public PolymorphicValidator<TInterface> Add<TDerived>(IValidator<TDerived> derivedValidator) where TDerived : TInterface {
_derivedValidators[typeof(TDerived)] = derivedValidator;
return this;
}
public override IValidator GetValidator(PropertyValidatorContext context) {
// bail out if the current item is null
if (context.PropertyValue == null) return null;
if (_derivedValidators.TryGetValue(context.PropertyValue.GetType(), out var derivedValidator)) {
return derivedValidator;
}
return null;
}
} You'd then use it like this: RuleForEach(p => p.Contacts).SetValidator(new PolymorphicValidator<IContact>()
.Add<Contact>(new ContactValidator())
.Add<Email>(new EmailValidator())
); (This is untested, but hopefully illustrates the point!) Edit 8th July 2020: For FluentValidation 9.x, the code will need to be updated slightly as Edit 26th August 2020 This is now available in FluentValidation 9.2. Please see here: https://docs.fluentvalidation.net/en/latest/inheritance.html |
Perfect. You've helped fill a gap in my knowledge and fix my issue. Thank you so much for your feedback |
System Details
Issue Description
I need to validate a collection of complex child objects on my object. I have created an AbstractValidator for each child, expecting to be able to use it in the Rule chain.
RuleForEach.SetValidator does not support AbstractValidator. The documentation leads me to believe it should. Presently it will only support PropertyValidator.
RuleForEach(x => x.Assets).SetValidator(new MyAssetValidator(myService));
Am I missing something?
The text was updated successfully, but these errors were encountered: