Правило 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.");
            }
        });