验证抛出 "Unable to cast object of type 'BaseModel' to type 'DerivedModel'."
Validation is throwing "Unable to cast object of type 'BaseModel' to type 'DerivedModel'."
当我尝试编写验证器时,我发现 FluentValidation (v8.2.0) 出现了一个奇怪的问题:
System.InvalidCastException
HResult=0x80004002
Message=Unable to cast object of type 'BaseModel' to type 'DerivedModel'.
Source=FluentValidation
StackTrace:
at FluentValidation.Internal.ConditionBuilder1.<>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()
at System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext()
at FluentValidation.AbstractValidator
1.Validate(ValidationContext`1 context) in C:\Projects\FluentValidation\src\FluentValidation\AbstractValidator.cs:line 115
at TestApp.Program.d__4.MoveNext() in C:\Users\john\Documents\Visual Studio 2017\Projects\TestApp\TestApp\Program.cs:line 76
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at TestApp.Program.(String[] args)
我的模型和验证器:
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);
,它可以正常工作。
导致此异常的原因是什么以及如何解决它?
我实际上偶尔会在我的 Web 应用程序中看到这个问题 - 99% 的时间它都可以正常工作,但偶尔我会遇到这个问题。我 reached out 给 FluentValidation 的作者 Jeremy Skinner,他解释了正在发生的事情:
Rules are intrinsicly tied to the validators that define them. They are not designed to be copied from one validator to another. They are inherently tied to the validator that defined them, and the type they were defined against.
Each condition block has a unique ID associated with it (that allows the result of the condition to be cached, so it's only executed one and not for each rule inside it). When you copy rules from one validator to another, the condition is brought across as well.
简而言之:您不能在验证器之间共享单个规则对象。
有问题的代码是来自 DerivedModelValidator
:
的这个块
foreach (var rule in baseValidator)
{
AddRule(rule);
}
Jeremy 针对这个问题提供了两种不同的解决方案:
1。从包含共享规则的公共基础验证器 class 派生两个验证器 classes:
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);
}
}
2。使用 SetValidator
:
从 BaseModelValidator
组成 DerivedModelValidator
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);
}
}
当我尝试编写验证器时,我发现 FluentValidation (v8.2.0) 出现了一个奇怪的问题:
System.InvalidCastException HResult=0x80004002 Message=Unable to cast object of type 'BaseModel' to type 'DerivedModel'. Source=FluentValidation StackTrace: at 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() at System.Linq.Enumerable.WhereEnumerableIterator1.MoveNext() at FluentValidation.AbstractValidator
1.Validate(ValidationContext`1 context) in C:\Projects\FluentValidation\src\FluentValidation\AbstractValidator.cs:line 115 at TestApp.Program.d__4.MoveNext() in C:\Users\john\Documents\Visual Studio 2017\Projects\TestApp\TestApp\Program.cs:line 76 at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at TestApp.Program.(String[] args)
我的模型和验证器:
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);
,它可以正常工作。
导致此异常的原因是什么以及如何解决它?
我实际上偶尔会在我的 Web 应用程序中看到这个问题 - 99% 的时间它都可以正常工作,但偶尔我会遇到这个问题。我 reached out 给 FluentValidation 的作者 Jeremy Skinner,他解释了正在发生的事情:
Rules are intrinsicly tied to the validators that define them. They are not designed to be copied from one validator to another. They are inherently tied to the validator that defined them, and the type they were defined against.
Each condition block has a unique ID associated with it (that allows the result of the condition to be cached, so it's only executed one and not for each rule inside it). When you copy rules from one validator to another, the condition is brought across as well.
简而言之:您不能在验证器之间共享单个规则对象。
有问题的代码是来自 DerivedModelValidator
:
foreach (var rule in baseValidator)
{
AddRule(rule);
}
Jeremy 针对这个问题提供了两种不同的解决方案:
1。从包含共享规则的公共基础验证器 class 派生两个验证器 classes:
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);
}
}
2。使用 SetValidator
:
从 BaseModelValidator
组成 DerivedModelValidator
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);
}
}