2012-08-14 7 views
40

Ich möchte ein benutzerdefiniertes Validierungsattribut erstellen, in dem ich den Wert meiner Eigenschaft mit dem Wert einer anderen Eigenschaft in meiner Modellklasse vergleichen möchte. Zum Beispiel habe ich in meinem Modell Klasse:Wie erstellt man ein benutzerdefiniertes Validierungsattribut?

...  
public string SourceCity { get; set; } 
public string DestinationCity { get; set; } 

Und ich möchte eine benutzerdefinierte erstellen Attribut es wie folgt zu verwenden:

[Custom("SourceCity", ErrorMessage = "the source and destination should not be equal")] 
public string DestinationCity { get; set; } 
//this wil lcompare SourceCity with DestinationCity 

Wie kann ich es bekommen?

+1

http://haacked.com/archive/2009/11/19/aspnetmvc2-custom-validation.aspx – Joe

+1

@Joe, das ist für ASP.NET MVC 2 und gilt nicht mehr für MVC 3. Auch dieses Blog Post zeigt nicht, wie ein abhängiger Eigenschaftswert im Validator abgerufen wird, was das OP hier zu erreichen versucht. –

Antwort

67

Hier ist, wie Sie den anderen Eigenschaftswert erhalten können:

public class CustomAttribute : ValidationAttribute 
{ 
    private readonly string _other; 
    public CustomAttribute(string other) 
    { 
     _other = other; 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     var property = validationContext.ObjectType.GetProperty(_other); 
     if (property == null) 
     { 
      return new ValidationResult(
       string.Format("Unknown property: {0}", _other) 
      ); 
     } 
     var otherValue = property.GetValue(validationContext.ObjectInstance, null); 

     // at this stage you have "value" and "otherValue" pointing 
     // to the value of the property on which this attribute 
     // is applied and the value of the other property respectively 
     // => you could do some checks 
     if (!object.Equals(value, otherValue)) 
     { 
      // here we are verifying whether the 2 values are equal 
      // but you could do any custom validation you like 
      return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName)); 
     } 
     return null; 
    } 
} 
+0

Großartig, das ist nur die Antwort ** Ich suche **! Nur mein Validierungskontext ist immer null. Irgendwelche Ideen? –

+2

@GrimmTheOpiner Ich weiß, das ist alt, aber für jeden, der sucht versuchen Sie 'öffentliche Überschreibung bool RequiresValidationContext {get {return true; }} 'in' CustomAttribute' – Ryan

+0

@Ryan Wow, warum wollte ich das tun? Selbst wenn ich mich erinnern könnte, ich bin jetzt zwei Jobs weiter! :-) –

4

Bitte schauen Sie unten für mein Beispiel:

Modellklasse Geräte INotifyPropertyChanged

public class ModelClass : INotifyPropertyChanged 
     { 
      private string destinationCity; 
      public string SourceCity { get; set; } 

      public ModelClass() 
      { 
       PropertyChanged += CustomAttribute.ThrowIfNotEquals; 
      } 

      [Custom("SourceCity", ErrorMessage = "the source and destination should not be equal")] 
      public string DestinationCity 
      { 
       get 
       { 
        return this.destinationCity; 
       } 

       set 
       { 
        if (value != this.destinationCity) 
        { 
         this.destinationCity = value; 
         NotifyPropertyChanged("DestinationCity"); 
        } 
       } 
      } 

      public event PropertyChangedEventHandler PropertyChanged; 

      protected virtual void NotifyPropertyChanged(string info) 
      { 
       if (PropertyChanged != null) 
       { 
        PropertyChanged(this, new PropertyChangedEventArgs(info)); 
       } 
      } 
     } 

Attributklasse auch enthält Ereignishendler.

internal sealed class CustomAttribute : Attribute 
    { 
     public CustomAttribute(string propertyName) 
     { 
      PropertyName = propertyName; 
     } 

     public string PropertyName { get; set; } 

     public string ErrorMessage { get; set; } 

     public static void ThrowIfNotEquals(object obj, PropertyChangedEventArgs eventArgs) 
     { 
      Type type = obj.GetType(); 
      var changedProperty = type.GetProperty(eventArgs.PropertyName); 
      var attribute = (CustomAttribute)changedProperty 
               .GetCustomAttributes(typeof(CustomAttribute), false) 
               .FirstOrDefault(); 

      var valueToCompare = type.GetProperty(attribute.PropertyName).GetValue(obj, null); 
      if (!valueToCompare.Equals(changedProperty.GetValue(obj, null))) 
       throw new Exception("the source and destination should not be equal"); 
     } 
    } 

Nutzungs

var test = new ModelClass(); 
    test.SourceCity = "1"; 
    // Everything is ok 
    test.DestinationCity = "1"; 
    // throws exception 
    test.DestinationCity ="2"; 

Code Zur Vereinfachung habe ich beschlossen, eine Validierung zu verzichten.