对特定流程最佳实践进行流畅的验证
本文关键字:验证 最佳 程最佳 | 更新日期: 2023-09-27 18:36:49
使用 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");
我对这种方法有两个问题:
- 我不喜欢使用字符串作为进程名称。我想使用更强类型的方法。例如,能够使用标记接口或属性。
- 在我的单元测试中,我无法设置 IValidator 的验证方法因为您不能将可选参数与最小起订量一起使用。
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.
What prevents you to create a helper class where you can use variables, data structures, anything you like to prevent the usage of hard-coded string parameters? Also, don't forget the possibility of using enums.
What prevents you from creating a class which implements IValidator where you can also implement custom functionality needed by you?
I have encountered the same issue and found out the reason why you can not mock this method via Moq etc validator.Validate(a, ruleSet: "ProcessA");
is because it is an extension method and Moq can't mock static methods.
Someone raised the same issue here in the FluentValidation issues: https://github.com/JeremySkinner/FluentValidation/issues/191
The simple solution is not to use the extension method rather use the instant method IValidator.validate(context)
. All you need to do is to build the context. Check out the source code from here: 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);