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
InvalidCastException when using ForEach rule #1711
Comments
Hi, thanks for reporting this, yes that's a bug. At the moment I don't see a good way of fixing this, so for now I'd suggest implementing a workaround and using an public SaveRegistrationRequestForHardwareUnitValidator(IValidator<UserDto> userDtoValidator)
{
//Other rules
var unitRoleCollectionValidator = new InlineValidator<IList<KeyValuePair<Guid,string>>>();
unitRoleCollectionValidator.RuleFor(r => r)
.Must(kv => HardwareUnitUserRoles.IsValid(kv.Value))
.WithMessage(m => Resources.ValidationMessages.hardwareunit_role_notvalid)
.Must(kv => kv.Value != HardwareUnitUserRoles.Owner)
.WithMessage(m => Resources.ValidationMessages.registrationrequest_hardwareUnitRole_notallowed)
RuleFor(r => r.HardwareUnitRoles).Cascade(CascadeMode.Stop)
.NotEmpty()
.SetValidator(unitRoleCollectionValidator)
.MustAsync((roles, token) => ValidRoleConfigAsync(roles))
.WithMessage(dto => ValidationErrorMessages.GetErrorMessage(ValidRoleConfigMessage));
} (this is essentially what the I'll post an update here if/when I find a way to fix this, but this should allow you to carry on with upgrading for now. |
Thanks for the feedback Jeremy. Looking forward to the fix. |
There isn't really any way to fix this now that the internal model is strongly typed (in 9.x and older the internal model wasn't generic, so the return types could be flexible like this). Now, the type returned by each part of the rule chain must be consistent. I think the only options are:
|
Some suggestions
Maybe a combination can be the key, so you only have one (private) implementation like suggestion 1 and many (public) overloads like suggestion 2. |
Unfortunately neither of these options will work properly- I’ve explored both in the past. Option 1 breaks compiler type inference, option 2 has the same problem as the original impl (variance will allow these overloads to be invoked on properties that are of a more derived type, leading to an invalid cast when accessing the internal api. It isn’t possible to cover every possible collection type) |
I think the way to support this properly would be extend the use of variance throughout the internal model rather than limiting it to the fluent API, but this would require several breaking changes so would have to wait for a major release. I think I'll leave |
I put together a quick prototype in #1713. Will need to think about whether the breaking changes this introduces will be problematic. |
I've committed a change in 6e825d3 which will allow this to work in 10.x without needing to introduce breaking changes (adds an additional interface, which can be removed again in v11). Well, technically there is one breaking change to the return type of one undocumented public method ( With this fix, the underlying problem will still be present if the user calls the I'll let you know once this is pushed to nuget so you can give it a try. |
I've published the 10.1 release to nuget with this fix. |
Updated our solution with the 10.1 version, set original validation code active again: all unit tests pass! |
FluentValidation version
10.0.4
ASP.NET version
.NET Core 3.1
Summary
I have a rulebuilder for a IList typed property with three rules: notEmpty, foreach and mustAsync. The problem is that the foreach rule returns a rulebuilder with out type 'IEnumerable' but the next rule seems to expect the original property type IList since there is an invalid cast exception from ...IList.. to ..IEnumerable..
This rule did not give any exception in FluentValidation version 9.3.0.
Steps to Reproduce
The code
Dto to validate
Validator
Exception:
The text was updated successfully, but these errors were encountered: