Правило FluentValidation для нулевого объекта
Я пытался выяснить, как создать правило FluentValidation, которое проверяет, не является ли экземпляр объекта, который он проверяет, нулевым, до проверки его свойств.
Я бы предпочел инкапсулировать эту нулевую проверку в валидатор, а не делать это в вызывающем коде.
см. пример кода ниже с комментариями, где требуется логика:
namespace MyNamespace
{
    using FluentValidation;
    public class Customer
    {
        public string Surname { get; set; }
    }
    public class CustomerValidator: AbstractValidator<Customer> 
    {
        public CustomerValidator() 
        {
            // Rule to check the customer instance is not null.
            // Don't continue validating.
            RuleFor(c => c.Surname).NotEmpty();
        }
    }
    public class MyClass
    {
        public void DoCustomerWork(int id)
        {
            var customer = GetCustomer(id);
            var validator = new CustomerValidator();
            var results = validator.Validate(customer);
            var validationSucceeded = results.IsValid;
        }
        public Customer GetCustomer(int id)
        {
            return null;
        }
    }
}
У меня вопрос как проверить CustomerValidator() конструктор, что текущий экземпляр customer не является null и прервать дальнейшую обработку правил, если она равна null?
спасибо заранее.
8 ответов
вы должны иметь возможность переопределить Validate метод CustomerValidator класса.
public class CustomerValidator: AbstractValidator<Customer> 
{
    // constructor...
    public override ValidationResult Validate(Customer instance)
    {
        return instance == null 
            ? new ValidationResult(new [] { new ValidationFailure("Customer", "Customer cannot be null") }) 
            : base.Validate(instance);
    }
}
Я не могу проверить это прямо сейчас, но вы можете попытаться переопределить Validate, или включить правила в When блок:
public CustomerValidator()
{
     When(x => x != null, () => {
         RuleFor(x => x.Surname).NotEmpty();
         //etc.
     });
}
для тех, кто использует версию >6.2.1, вам нужно переопределить эту подпись, чтобы достичь того же, что и @chrispr:
public override ValidationResult Validate(ValidationContext<T> context)
{
    return (context.InstanceToValidate == null) 
        ? new ValidationResult(new[] { new ValidationFailure("Property", "Error Message") })
        : base.Validate(context);       
}
я унаследовал от fluent AbstractValidator и создал вместо этого класс NullReferenceAbstractValidator:
public class NullReferenceAbstractValidator<T> : AbstractValidator<T>
{
    public override ValidationResult Validate(T instance)
    {
        return instance == null
            ? new ValidationResult(new[] { new ValidationFailure(instance.ToString(), "response cannot be null","Error") })
            : base.Validate(instance);
    }
}
и затем наследуется от этого класса с каждым валидатором, который нуждался в проверке нулевой ссылки:
public class UserValidator : NullReferenceAbstractValidator<User>
поскольку вышеуказанные решения не работали для меня (FluentValidation, Version=6.2.1.0 для Net45), я публикую то, что я сделал.
Это просто простая замена / обертка для ValidateAndThrow метод расширения.
public static class ValidatorExtensions
{
    public static void ValidateAndThrowNotNull<T>(this IValidator<T> validator, T instance)
    {
        if (instance == null)
        {
            var validationResult = new ValidationResult(new[] { new ValidationFailure("", "Instance cannot be null") });
            throw new ValidationException(validationResult.Errors);
        }
        validator.ValidateAndThrow(instance);
    }
}
используйте каскадный режим.
вот пример документация.
RuleFor(x => x.Surname).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEqual("foo");
также из документации:
если валидатор NotNull не выполняется, то валидатор NotEqual не будет выполненный. Это особенно полезно, если у вас сложная цепочка где каждый валидатор зависит от предыдущего валидатора для успеха.
переопределить EnsureInstanceNotNull как показано ниже
protected override void EnsureInstanceNotNull(object instanceToValidate)
{
    if(instanceToValidate==null)
      throw new ValidationException("Customer can not be null");
}
С помощью Custom (). Это также может быть очень полезно, когда проверка другого поля основана на проверке вашего текущего поля.
ruleBuilder.Custom((obj, context) =>
        {
            if (obj != null)
            {
                var propertyName = <field where should be validation>;
                context.AddFailure(propertyName, "'Your field name' Your validation message.");
            }
        });
