使用http://fluentvalidation.codeplex.com/将验证规则绑定到特定进程的最佳实践是什么?
目前我正在使用“规则集”功能将规则分组到不同的进程:
public class ObjAValidation: AbstractValidator<A>
{
public ObjAValidation()
{
RuleSet("ProcessA", () =>
{
RuleFor(x => ...);
RuleFor(x => ...);
});
RuleSet("ProcessB", () =>
{
RuleFor(x => ...);
RuleFor(x => ...);
});
}
}
然后验证使用:
var a = new A(){...};
IValidator<A> validator = new ObjAValidation();
var result = validator.Validate(a, ruleSet: "ProcessA");
这种方法有两个问题:
Mock<IValidator<A>> _mockValidator = new Mock<IValidator<A>>();
_mockValidator.Setup(x => x.Validate(new A(), ruleSet: "ProcessA"));
Second line generates a run time error: An expression tree may not contain a named argument specification. And if you want to pass the ruleSet argument without a named argument to Validate method you have to provide a "IValidatorSelector selector" object. But this interface is not documented.
什么阻止您创建一个帮助器类,您可以使用变量,数据结构,任何您喜欢的东西来阻止使用硬编码的字符串参数?另外,不要忘记使用枚举的可能性。
什么阻止您创建一个实现IValidator的类,您还可以在其中实现您需要的自定义功能?
我遇到了同样的问题,并找出了为什么你不能通过Moq等模拟这个方法的原因validator.Validate(a, ruleSet: "ProcessA");
是因为它是一个扩展方法而且Moq不能模拟静态方法。
有人在FluentValidation问题中提出了同样的问题:https://github.com/JeremySkinner/FluentValidation/issues/191
简单的解决方案是不使用扩展方法而是使用即时方法IValidator.validate(context)
。您需要做的就是构建上下文。查看源代码:https://github.com/JeremySkinner/FluentValidation/blob/master/src/FluentValidation/DefaultValidatorExtensions.cs#L819
if(ruleSet != null) {
var ruleSetNames = ruleSet.Split(',', ';').Select(x => x.Trim());
selector = ValidatorOptions.ValidatorSelectors.RulesetValidatorSelectorFactory(ruleSetNames.ToArray());
}
var context = new ValidationContext<T>(instance, new PropertyChain(), selector);
return validator.Validate(context);