Fluent验证规则、子集和嵌套

本文关键字:嵌套 子集 验证 规则 Fluent | 更新日期: 2023-09-27 18:27:16

给定一个类似的验证器类

 public class SomeValidator : AbstractValidator<SomeObject>
 {
      public SomeValidator(){
           RuleSet("First",
                () => {
                     RuleFor(so => so.SomeMember).SetValidator(new SomeMemberValidator())
           });
           RuleSet("Second",
                () => ... Code Does Not Matter ... );
           RuleSet("Third",
                () => ... Code Does Not Matter ... );
      }
 }

和另一个做内部成员验证

 public class SomeMemberValidator: AbstractValidator<SomeMember>
 {
      public SomeValidator(){
           RuleSet("Fourth",
                () => {
                     ... Code Does Not Matter ...
           });
      }
 }

问题是,我想运行特定的规则集:"第一"、"第二"answers"第四"。我不想让"第三"跑。

鉴于Validate方法签名只接受一个规则集参数,我看不出有任何方法可以做到这一点。有"*",但我不想执行所有规则。

请帮忙。

Fluent验证规则、子集和嵌套

您可以使用验证器构造函数而不是RuleSet来解决此问题。只需在验证器类内部创建枚举,然后在创建验证器时使用其值。

通过这种方式,正确的规则将被激活,这取决于构造函数中设置的模式。

public class UserValidator : AbstractValidator<User>
{
    public enum Mode
    {
        Create,
        Edit
    }
    public UserValidator()
    {
        // Default rules...
    }
    public UserValidator(UserValidator.Mode mode)
        : this()
    {
        if (mode == Mode.Edit)
        {
            // Rules for Edit...
            RuleFor(so => so.SomeMember)
                .SetValidator(
                    new SomeMemberValidator(SomeMemberValidator.Mode.SomeMode))
        }
        if (mode == Mode.Create)
        {
            // Rules for Create...
            RuleFor(so => so.SomeMember)
                .SetValidator(
                    new SomeMemberValidator())
        }
    }
}

我认为它实际上比使用RuleSet更灵活。

关于FluentValidation MVC集成,只有一个小问题:User类不能具有属性[Validator(typeof(UserValidator))],因为在控制器方法中执行任何操作之前,将使用默认构造函数创建UserValidator。

必须手动创建和调用验证器。例如:

public class UserController : Controller
{
    [HttpPost]
    public ActionResult Create(User userData)
    {
        var validator = new UserValidator(UserValidator.Mode.Create);
        if (ValidateWrapper(validator, userData, this.ModelState))
        {
            // Put userData in database...
        }
        else
        {
            // ValidateWrapper added errors from UserValidator to ModelState.
            return View();
        }
    }
    private static bool ValidateWrapper<T>(FluentValidation.AbstractValidator<T> validator, T data, ModelStateDictionary modelState)
    {
        var validationResult = validator.Validate(data);
        if (!validationResult.IsValid)
        {
            foreach (var error in validationResult.Errors)
                modelState.AddModelError(error.PropertyName, error.ErrorMessage);
            return false;
        }
        return true;
    }
}

您可以执行多个RuleSet,但我认为您不能执行内部RuleSet。

validator.Validate(new ValidationContext<SomeObject>(person, new PropertyChain(), new RulesetValidatorSelector("First", "Second", "Fourth")));

另一种选择是研究源代码并尝试想出一种方法。ValidationContext的第三个参数是接口IValidatorSelector,也许你可以幸运地使用自定义类。