web-dev-qa-db-fra.com

Règle FluentValidation pour un objet null

J'ai essayé de créer une règle FluentValidation qui vérifie si l'instance d'un objet en cours de validation n'est pas nulle avant de valider ses propriétés. 

Je préférerais encapsuler cette validation nulle dans le validateur plutôt que de le faire dans le code appelant.

Voir l'exemple de code ci-dessous avec des commentaires pour lesquels la logique requise est requise:

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;
        }
    }
}

Ma question est donc la suivante: comment puis-je vérifier dans le constructeur CustomerValidator () que l'instance actuelle du client n'est pas nulle et interrompre le traitement de la règle s'il est null ?

Merci d'avance.

30
Bern

Vous devriez pouvoir remplacer la méthode Validate dans votre classe 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);
    }
}
26
Matthew

Je ne peux pas vraiment tester cela pour l'instant, mais vous pouvez soit essayer de remplacer Validate, soit inclure les règles dans le bloc When:

public CustomerValidator()
{
     When(x => x != null, () => {
         RuleFor(x => x.Surname).NotEmpty();
         //etc.
     });
}
12
Patryk Ćwiek

Pour ceux qui utilisent la version> 6.2.1, vous devez remplacer cette signature afin d'obtenir le même résultat que @chrispr:

public override ValidationResult Validate(ValidationContext<T> context)
{
    return (context.InstanceToValidate == null) 
        ? new ValidationResult(new[] { new ValidationFailure("Property", "Error Message") })
        : base.Validate(context);       
}
6
Elmar

J'ai hérité du abstractValidator courant et créé une classe NullReferenceAbstractValidator à la place:

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);
    }
}

puis hérité de cette classe avec chaque validateur ayant besoin d'une vérification de référence nulle:

public class UserValidator : NullReferenceAbstractValidator<User>
2
chrispr

Comme les solutions ci-dessus ne fonctionnaient pas pour moi (FluentValidation, Version = 6.2.1.0 pour Net45), je publie ce que j'ai fait. C'est juste un simple remplacement/wrapper pour la méthode d'extension 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);
    }
}
1
Lee Campbell

Utilisez le mode Cascade.

Voici l'exemple de la documentation .

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

Aussi de la documentation:

Si le validateur NotNull échoue, le validateur NotEqual ne sera pas réalisé. Ceci est particulièrement utile si vous avez une chaîne complexe où chaque validateur dépend du validateur précédent pour réussir.

1
Trevor

Au moyen de Custom (). Cela peut aussi être très utile lorsque la validation d’un autre champ est basée sur la validation de votre champ actuel.

ruleBuilder.Custom((obj, context) =>
        {
            if (obj != null)
            {
                var propertyName = <field where should be validation>;
                context.AddFailure(propertyName, "'Your field name' Your validation message.");
            }
        });
1
user7617828

Remplacez EnsureInstanceNotNull comme ci-dessous

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

Ceci est une publication plus ancienne, mais vous souhaitez mettre à jour les réponses pour inclure les éléments suivants de la documentation de FluentValidation:

Utiliser PreValidate

Si vous devez exécuter un code spécifique chaque fois qu'un validateur est appelé, vous pouvez le faire en substituant la méthode PreValidate. Cette méthode utilise un ValidationContext ainsi qu'un ValidationResult, que vous pouvez utiliser pour personnaliser le processus de validation.

public class MyValidator : AbstractValidator<Person> {
  public MyValidator() {
    RuleFor(x => x.Name).NotNull();
  }

  protected override bool PreValidate(ValidationContext<Person> context, ValidationResult result) {
    if (context.InstanceToValidate == null) {
      result.Errors.Add(new ValidationFailure("", "Please ensure a model was supplied."));
      return false;
    }
    return true;
  }
}

https://fluentvalidation.net/start#using-prevalidate

0
camainc