FluentValidation несколько валидаторов
могу ли я добавить более одного валидатора к объекту? Например:
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());
}
}
запуск теста.
FooBarValidator validator = new FooBarValidator();
validator.ShouldHaveValidationErrorFor(x => x.Id, 0);
Я InvalidOperationException
:
имя свойства не может быть автоматически определено для выражения x => x. Пожалуйста, укажите имя настраиваемого свойства, вызвав "WithName".
есть ли способ реализовать это или я пытаюсь использовать FluentValidation таким образом, что он не предназначен для использования?
3 ответов
взяли ее за правило для пытается создать свойство-уровень правило. Можно также использовать функцию AddRule для добавления правила общего назначения.
используя это, я создал составное доказательство правила концепции. Он принимает набор других валидаторов и запускает их. The yield break
код пришел сразу с FluentValidator
' s DelegateValidator
. Я не был уверен, что с ним делать, поэтому я схватил это из источника. Я не проследил его полное назначение, но все, кажется, работает как есть :)
код
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()));
}
}
Базовый Тест:
[TestMethod]
public void TestValidator()
{
FooBarValidator validator = new FooBarValidator();
var result = validator.Validate(new FooBar());
}
надеюсь, это поможет.
другой возможностью было бы переопределить 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);
}
вы можете использовать наборы правил для применения различных типов проверки, если это помогает в том, что вы пытаетесь сделать: