对特定流程最佳实践进行流畅的验证

本文关键字:验证 最佳 程最佳 | 更新日期: 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");

我对这种方法有两个问题:

  1. 我不喜欢使用字符串作为进程名称。我想使用更强类型的方法。例如,能够使用标记接口或属性。
  2. 在我的单元测试中,我无法设置 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);