2016-07-18 1 views
2

Dans ma classe de validateurs, j'ai quelques règles.
Je dois enregistrer dans la base de données certaines erreurs de validation.FluentValidation LogOnFailure override

Voici mes validateurs:

RuleFor(u => u.LastName) 
    .Cascade(CascadeMode.StopOnFirstFailure) 
    .NotEmpty().WithMessage("Last name is required") 
    .Length(3, 20).WithMessage("Must have between 3 and 20 letters"); 

RuleFor(u => u.BirthDate) 
    .Cascade(CascadeMode.StopOnFirstFailure) 
    .NotNull().WithMessage("Birth date is required") 
    .Must(c => c > new DateTime(1920, 01, 01)).WithMessage("Too old"); 

RuleFor(u => u.Age) 
    .Cascade(CascadeMode.StopOnFirstFailure) 
    .NotNull().WithMessage("This is required") 
    .GreaterThan(18).WithMessage("Must be at least 18") 
    .Must((model, age, context) => 
    { 
     DateTime today = DateTime.Today; 
     int ageToCompare = today.Year - model.BirthDate.Year; 
     return ageToCompare == age; 
    }).WithMessage("Invalid age"); 

Pour connaître les règles ci-dessus que je voudrais enregistrer des messages d'erreur spécifiques uniquement. Je suis conscient que je peux utiliser OnAnyFailure comme ceci:

RuleFor(u => u.Age) 
    .Cascade(CascadeMode.StopOnFirstFailure) 
    .NotNull().WithMessage("This is required") 
    .GreaterThan(18).WithMessage("Must be at least 18").OnAnyFailure(LogOnFailure) 
    .Must((model, age, context) => 
    { 
     DateTime today = DateTime.Today; 
     int ageToCompare = today.Year - model.BirthDate.Year; 
     return ageToCompare == age; 
    }).WithMessage("Invalid age").OnAnyFailure(LogOnFailure) 

private void LogOnFailure(CreateAccountBindingModel obj)) 
    { 
     Debug.WriteLine(obj); 
    } 

mais cette façon, je ne pourrai rien connecter utile, car OnAnyFailure prend BindingModel en tant que paramètre, donc je vais seulement obtenir des valeurs entrées par l'utilisateur sans messages d'erreur.

J'ai essayé de créer une méthode d'extension qui fonctionnerait comme OnAnyFailure mais comme je suis nouveau dans FluentValidation, je n'ai même pas pu compiler mon code.

Ci-dessous mon code:

public static class IRuleBuilderOptionsExtensions 
{ 
    public static IRuleBuilderOptions<T, TProperty> OnAnyFailure<T, TProperty>(this IRuleBuilderOptions<T, TProperty> rule, Action<T, PropertyValidatorContext> onFailure) 
    { 
     return rule; 
     //return rule.Configure(config => { 
     // config.OnFailure = onFailure.CoerceToNonGeneric(); 
     //}); 
    } 
} 

De cette façon, je pourrais être en mesure d'appeler:

private void LogOnFailure(CreateAccountBindingModel obj), PropertyValidatorContext context) 
{ 
    //log logic 
} 

Fondamentalement, ce que j'ai besoin est de créer override pour LogOnFailure qui sera en mesure d'accéder PropertyValidatorContext.

+0

Création dérogation ne sera pas utile, car le cadre appellera 'PropertyRule.OnFailure' avec un seul paramètre (par exemple pour valider). –

+0

@AlekseyL. Alors y a-t-il un autre moyen? Le nom de la méthode peut être différent, il ne doit pas être prioritaire. Je voudrais obtenir mon modèle et PropertyValidationContext lorsqu'une erreur survient, tout comme 'OnAnyFailure' – Misiu

+0

Je ne suis pas au courant d'un tel point d'extensibilité, mais vous pouvez le faire dans' ActionFilter' - vérifier l'état du modèle et consigner toutes les erreurs. Faites-moi savoir si vous avez besoin d'un exemple pour cela. –

Répondre

0

Vous pouvez valider votre modèle deuxième fois pour l'afficher:

public class MyValidator 
{ 
    public MyValidator() 
    { 
     // default behavior 
     Validate(); 

     // works only when RuleSet specified explicitly as "Debug" 
     RuleSet("Debug",()=> { 
      Validate(); 
      FailAndLogErrors(); 
     }) 

     private void Validate() 
     { 
      RuleFor(u => u.Age) 
       //... set cascade mode, define rules with error messages 
      RuleFor(u => u.LastName) 
       //... set cascade mode, define rules with error messages 
      RuleFor(u => u.BirthDate) 
       //... set cascade mode, define rules with error messages 
     } 

     // force failing 
     private void FailAndLogErrors() 
     { 
      RuleFor(m => m) 
       .Must(m => false) 
       .WithName("_fakeProperty_") 
       .OnAnyFailure(m => LogIfFailed(this, m)) 
     } 

     private void LogIfFailed(MyValidator validator, CreateAccountBindingModel obj)) 
     { 
      var errors = validator.Validate(obj, "Debug").Errors; 
      if (errors.Count > 1) // prevent displaying valid model 
      { 
       var fakeError = errors.First(e => e.PropertyName == "_fakeProperty_"); 
       errors.Remove(fakeError); 
       WriteErrors(errors); 
      } 
     } 

     private void WriteErrors(IList<ValidationFailure> errors) 
     { 
      foreach(var e in errors) 
      { 
       Debug.WriteLine(e); 
      } 
      Debug.WriteLine(""); 
     } 
    } 
}