当我尝试编写验证器时,我发现FluentValidation(v8.2.0)有一个奇怪的问题:
System.InvalidCastException HResult = 0x80004002 Message =无法将类型为“ BaseModel”的对象转换为类型为“ DerivedModel”的对象。 来源= FluentValidation 堆栈跟踪: 在FluentValidation.Internal.ConditionBuilder
1.<>c__DisplayClass2_0.<When>g__Condition|0(ValidationContext context) in C:\Projects\FluentValidation\src\FluentValidation\Internal\ConditionBuilder.cs:line 62 at FluentValidation.Internal.PropertyRule.<Validate>d__67.MoveNext() in C:\Projects\FluentValidation\src\FluentValidation\Internal\PropertyRule.cs:line 270 at System.Linq.Enumerable.SelectManySingleSelectorIterator
2.MoveNext() 在System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext() at FluentValidation.AbstractValidator
1.Validate(ValidationContext`1上下文)在C:\ Projects \ FluentValidation \ src \ FluentValidation \ AbstractValidator.cs:line 115中 在C:\ Users \ john \ Documents \ Visual Studio 2017 \ Projects \ TestApp \ TestApp \ Program.cs:line 76中的TestApp.Program.d__4.MoveNext() 在System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() 在System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在TestApp.Program。(字符串[]参数)
public class BaseModel
{
public string Name { get; set; }
public bool IsAlive { get; set; }
}
public class DerivedModel : BaseModel
{
public int Age { get; set; }
}
public class BaseModelValidator : AbstractValidator<BaseModel>
{
public BaseModelValidator()
{
RuleFor(o => o.Name).Length(1, 20);
}
}
public class DerivedModelValidator : AbstractValidator<DerivedModel>
{
public DerivedModelValidator(BaseModelValidator baseValidator)
{
foreach (var rule in baseValidator)
{
AddRule(rule);
}
RuleFor(o => o.Age).GreaterThanOrEqualTo(0);
}
}
var baseModelValidator = new BaseModelValidator();
var derivedModelValidator = new DerivedModelValidator(baseModelValidator);
var baseModel = new BaseModel
{
IsAlive = true,
Name = "test2"
};
Console.WriteLine(baseModelValidator.Validate(baseModel).IsValid);
如您所见,我正在使用BaseModelValidator
来验证BaseModel
,并且在任何地方都没有引用DerivedModel
。
很有趣的是,如果我删除了var derivedModelValidator = new DerivedModelValidator(baseModelValidator);
行,它就可以正常工作了。
是什么原因导致此异常以及如何解决?
答案 0 :(得分:1)
我实际上在我的Web应用程序中偶尔看到此问题-99%的时间它可以正常工作,但有时我会遇到此问题。我reached out向作者或FluentValidation的杰里米·斯金纳(Jeremy Skinner)解释了发生了什么事:
规则本质上与定义它们的验证器相关。不能将它们从一个验证器复制到另一个验证器。它们本质上与定义它们的验证器以及定义它们的类型相关。
每个条件块都有一个与之关联的唯一ID(允许条件条件的结果被缓存,因此它仅执行一个,而不针对其中的每个规则执行)。当您将规则从一个验证器复制到另一个验证器时,条件也会同时出现。
简而言之:您不能在验证者之间共享单个规则对象。
令人讨厌的代码段是DerivedModelValidator
的以下代码段:
foreach (var rule in baseValidator)
{
AddRule(rule);
}
Jeremy针对此问题提供了两种不同的解决方案:
public abstract class CommonModelValidator<T> : AbstractValidator<T> where T : BaseModel
{
protected CommonModelValidator()
{
RuleFor(o => o.Name).Length(1, 20);
}
}
public class BaseModelValidator : CommonModelValidator<BaseModel>
{
}
public class DerivedModelValidator : CommonModelValidator<DerivedModel>
{
public DerivedModelValidator(BaseModelValidator baseValidator)
: base()
{
RuleFor(o => o.Age).GreaterThanOrEqualTo(0);
}
}
DerivedModelValidator
从BaseModelValidator
组成SetValidator
:public class BaseModelValidator : AbstractValidator<BaseModel>
{
public BaseModelValidator()
{
RuleFor(o => o.Name).Length(1, 20);
}
}
public class DerivedModelValidator : AbstractValidator<DerivedModel>
{
public DerivedModelValidator(BaseModelValidator baseValidator)
{
RuleFor(o => o).SetValidator(baseValidator);
RuleFor(o => o.Age).GreaterThanOrEqualTo(0);
}
}