Правило FluentValidation для нулевого объекта
Я пытался выяснить, как создать правило FluentValidation, которое проверяет, не является ли экземпляр объекта, который он проверяет, не является нулевым до проверки его свойств.
Я предпочел бы инкапсулировать эту нулевую проверку в Validator, а не делать ее в вызывающем коде.
См. пример кода ниже с комментариями, где требуется требуемая логика:
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(), что текущий экземпляр клиента не является нулевым и прервать обработку дополнительных правил, если он равен null?
Спасибо заранее.
Ответы
Ответ 1
Вы можете переопределить метод 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);
}
}
Ответ 2
Я не могу проверить это прямо сейчас, но вы можете либо попробовать переопределить Validate
, либо включить правила в блок When
:
public CustomerValidator()
{
When(x => x != null, () => {
RuleFor(x => x.Surname).NotEmpty();
//etc.
});
}
Ответ 3
Я унаследовал от абстрактного 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>
Ответ 4
Поскольку приведенные выше решения не сработали для меня (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);
}
}
Ответ 5
Для тех, кто использует версию > 6.2.1, вам нужно переопределить эту подпись, чтобы добиться того же, что и @chrispr:
public override ValidationResult Validate(ValidationContext<T> context)
{
return (context.InstanceToValidate == null)
? throw new ValidationResult(new[] { new ValidationFailure("Property", "Error Message") })
: base.Validate(context);
}
Ответ 6
Используйте каскадный режим.
Вот пример из документации.
RuleFor(x => x.Surname).Cascade(CascadeMode.StopOnFirstFailure).NotNull().NotEqual("foo");
Также из документации:
Если отказоустойчивость NotNull не выполняется, то средство проверки NotEqual не будет казнены. Это особенно полезно, если у вас сложная цепочка где каждый валидатор зависит от предыдущего валидатора для успеха.
Ответ 7
Переопределить EnsureInstanceNotNull, как показано ниже
protected override void EnsureInstanceNotNull(object instanceToValidate)
{
if(instanceToValidate==null)
throw new ValidationException("Customer can not be null");
}