简体   繁体   English

FluentValidation 多个验证器

[英]FluentValidation multiple validators

Can I add more than one validator to an object?我可以向一个对象添加多个验证器吗? For example:例如:

public interface IFoo
{
    int Id { get; set; }
    string Name { get; set; }
}

public interface IBar
{
    string Stuff { get; set; }
}

public class FooValidator : AbstractValidator<IFoo>
{
    public FooValidator ()
    {
        RuleFor(x => x.Id).NotEmpty().GreaterThan(0);
    }
}

public class BarValidator : AbstractValidator<IBar>
{
    public BarValidator()
    {
        RuleFor(x => x.Stuff).Length(5, 30);
    }
}

public class FooBar : IFoo, IBar
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Stuff { get; set; }
}

public class FooBarValidator : AbstractValidator<FooBar>
{
    public FooBarValidator()
    {
        RuleFor(x => x)
            .SetValidator(new FooValidator())
            .SetValidator(new BarValidator());
    }
}

Running the test.运行测试。

FooBarValidator validator = new FooBarValidator();
validator.ShouldHaveValidationErrorFor(x => x.Id, 0);

I get an InvalidOperationException :我得到一个InvalidOperationException

Property name could not be automatically determined for expression x => x.无法为表达式 x => x 自动确定属性名称。 Please specify either a custom property name by calling 'WithName'.请通过调用“WithName”指定自定义属性名称。

Is there any way to implement this or am I trying to use FluentValidation in a way that it's not meant to be used?有什么方法可以实现这一点,还是我试图以一种不打算使用的方式使用 FluentValidation?

RuleFor is trying to create a property-level rule. RuleFor 正在尝试创建属性级规则。 You can additionally use the AddRule function to add a general-purpose rule.您还可以使用 AddRule 函数添加通用规则。

Using this, I created a composite rule proof of concept.使用这个,我创建了一个复合规则概念证明。 It takes in a set of other validators and runs them.它接收一组其他验证器并运行它们。 The yield break code came straight from FluentValidator 's DelegateValidator . yield break代码直接来自FluentValidatorDelegateValidator I wasn't sure what to do with it so I grabbed that from the source.我不知道该怎么处理它,所以我从源头上抓住了它。 I didn't trace its full purpose, but everything seems to work as is :)我没有追踪它的全部目的,但一切似乎都按原样工作:)

Code代码

public interface IFoo
{
    int Id { get; set; }
    string Name { get; set; }
}

public interface IBar
{
    string Stuff { get; set; }
}

public class FooValidator : AbstractValidator<IFoo>
{
    public FooValidator()
    {
        RuleFor(x => x.Id).NotEmpty().GreaterThan(0);
    }
}

public class BarValidator : AbstractValidator<IBar>
{
    public BarValidator()
    {
        RuleFor(x => x.Stuff).Length(5, 30);
    }
}

public class FooBar : IFoo, IBar
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Stuff { get; set; }
}

public class CompositeValidatorRule : IValidationRule
{
    private IValidator[] _validators;

    public CompositeValidatorRule(params IValidator[] validators)
    {
        _validators = validators;
    }

    #region IValidationRule Members
    public string RuleSet
    {
        get; set;
    }

    public IEnumerable<ServiceStack.FluentValidation.Results.ValidationFailure> Validate(ValidationContext context)
    {
        var ret = new List<ServiceStack.FluentValidation.Results.ValidationFailure>();

        foreach(var v in _validators)
        {
            ret.AddRange(v.Validate(context).Errors);
        }

        return ret;
    }

    public IEnumerable<ServiceStack.FluentValidation.Validators.IPropertyValidator> Validators
    {
        get { yield break; }
    }
    #endregion
}

public class FooBarValidator : AbstractValidator<FooBar>
{
    public FooBarValidator()
    {
        AddRule(new CompositeValidatorRule(new FooValidator(), new BarValidator()));
    }
}

Base Test Case:基本测试用例:

    [TestMethod]
    public void TestValidator()
    {
        FooBarValidator validator = new FooBarValidator();
        var result = validator.Validate(new FooBar());

    }

I hope this helps.我希望这有帮助。

Another possibility would be to override Validate:另一种可能性是覆盖验证:

public override ValidationResult Validate(ValidationContext<FooBar> context)
{
    var fooResult = new FooValidator().Validate(context.InstanceToValidate);
    var barResult = new BarValidator().Validate(context.InstanceToValidate);

    var errors = new List<ValidationFailure>();
    errors.AddRange(fooResult.Errors);
    errors.AddRange(barResult.Errors);

    return new ValidationResult(errors);
}

"Including Rules. You can include rules from other validators provided they validate the same type." “包括规则。你可以包括来自其他验证器的规则,前提是它们验证相同的类型。”

public class PersonValidator : AbstractValidator<Person> {
    public PersonValidator() {
        Include(new PersonAgeValidator());
        Include(new PersonNameValidator());
    }
}

https://docs.fluentvalidation.net/en/latest/including-rules.html https://docs.fluentvalidation.net/en/latest/include-rules.html

You could use RuleSets to apply different types of validation if that helps with what you are trying to do:如果这有助于您尝试执行的操作,您可以使用规则集来应用不同类型的验证:

FluentValidation RuleSets FluentValidation 规则集

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM