2016-07-18 5 views
2

Innerhalb meiner Validierungsklasse habe ich einige Regeln.
Ich muss einige Validierungsfehler in der Datenbank protokollieren.FluentValidation LogOnFailure override

Hier sind meine Validatoren:

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

Für über Regeln, die ich nur bestimmte Fehlermeldungen protokollieren möchte. Ich bin mir bewusst, dass ich so verwenden OnAnyFailure kann:

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

aber auf diese Weise will ich etwas Sinnvolles zu protokollieren, weil OnAnyFailure nimmt BindingModel als Parameter nicht in der Lage sein, also werde ich Werte Benutzer nur eingegeben erhalten ohne Fehlermeldungen.

Ich habe versucht, eine Erweiterungsmethode zu erstellen, die als OnAnyFailure funktionieren würde, aber weil ich neu bei FluentValidation bin, war ich nicht in der Lage, sogar meinen Code zu kompilieren.

Unten ist mein 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(); 
     //}); 
    } 
} 

Auf diese Weise ich in der Lage sein könnte, zu nennen:

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

Im Grunde, was ich brauche, ist Überschreibung für LogOnFailure zu schaffen, die die Lage sein wird PropertyValidatorContext zuzugreifen.

+0

Erstellen von Überschreibung wird nicht helfen, da das Framework 'PropertyRule.OnFailure' mit einzelnen Parametern nennen (Beispiel zur Validierung). –

+0

@AlekseyL. Gibt es einen anderen Weg? Der Name der Methode kann unterschiedlich sein, sie muss nicht überschrieben werden. Ich möchte mein Modell und PropertyValidationContext erhalten, wenn ein Fehler auftritt, genau wie 'OnAnyFailure' – Misiu

+0

Ich bin nicht bewusst, solche Erweiterungspunkt, aber Sie können dies in' ActionFilter' tun - überprüfen Sie den Modellstatus und protokollieren Sie alle Fehler. Lass es mich wissen, wenn du ein Beispiel dafür brauchst. –

Antwort

0

Sie können Ihr Modell zweites Mal bestätigen, um sie anzuzeigen:

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