2013-06-13 2 views
23

Я пытался выяснить, как создать правило 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() конструктор, что текущий экземпляр клиента не является нулевым и отменить дальнейшую обработку правила, если она равна нулю?

Заранее спасибо.

+2

Переопределить метод 'Validate'? – Matthew

+0

У вас есть метод расширения, который проверяет, имеет ли он значение null перед вызовом базового метода Validate()? – Bern

+0

Нет, см. Мой ответ ниже. Вы бы назвали его так же, как и любой другой валидатор. – Matthew

ответ

22

Вы должны иметь возможность переопределить метод 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); 
    } 
} 
+0

Хорошая работа @Matthew, солидный ответ. – Bern

+0

Вы могли бы даже сократить его до: return instance == null ? new ValidationResult (new [] {new ValidationFailure («Клиент», «Клиент не может быть null»)}) : base.Validate (instance); – Bern

+2

Я использую последнюю версию FluentValidation, и Validate() даже не срабатывает для меня. Это больше не кажется возможным. –

10

Я не могу проверить это прямо сейчас, но вы можете либо попытаться переопределить Validate или включить правила в When блоке:

public CustomerValidator() 
{ 
    When(x => x != null,() => { 
            RuleFor(x => x.Surname).NotEmpty(); 
            //etc. 
           }); 
} 
+0

Приятно, но есть способ, которым я могу применить к нему сообщение проверки, то есть .WithMessage («Клиент не существует»); ? – Bern

+1

@Bern Возможно, вы могли бы сделать «RuleFor (x => x) .NotNull(). WithMessage (« Клиент не существует »);', но вне блока 'When'? –

+0

Спасибо, да, я пробовал это, и это заставило исключение. Я думаю, что @Matthew удалось прибить его выше. – Bern

2

я унаследовал от беглого 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> 
+12

Почему вы делаете instance.ToString(), когда экземпляр null? – pomber

1

Поскольку приведенные выше решения не сработали для меня (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); 
    } 
} 
3

Для тех, кто использует версию> 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);  
} 
+0

Этот метод не запускается для WebApi. – Maybe

1

Используйте режим Cascade.

Вот пример из documentation.

RuleFor(x => x.Surname).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEqual("foo"); 

Кроме того, из документации:

Если NotNull валидатор не работает, то NotEqual валидатор не будет выполняться. Это особенно полезно, если у вас есть сложная цепочка , где каждый валидатор зависит от предыдущего валидатора для успеха.

0

Переопределение EnsureInstanceNotNull, как показано ниже

protected override void EnsureInstanceNotNull(object instanceToValidate) 
{ 
    if(instanceToValidate==null) 
     throw new ValidationException("Customer can not be null"); 
} 
0

обычным путем().Это может быть очень полезно, когда проверка другого поля основана на проверке вашего текущего поля.

ruleBuilder.Custom((obj, context) => 
     { 
      if (obj != null) 
      { 
       var propertyName = <field where should be validation>; 
       context.AddFailure(propertyName, "'Your field name' Your validation message."); 
      } 
     }); 
Смежные вопросы