2012-08-14 27 views
40

Quiero crear un atributo de validación personalizado, en el que quiero comparar el valor de mi propiedad con el valor de otra propiedad en mi clase de modelo. Por ejemplo, tengo en mi clase del modelo:¿Cómo crear un atributo de validación personalizado?

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

Y yo quiero crear un atributo personalizado a utilizar de esta manera:

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

¿Cómo puedo llegar?

+1

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

+1

@Joe, eso es para ASP.NET MVC 2 y ya no se aplica a MVC 3. También este blog La publicación no ilustra cómo recuperar un valor de propiedad dependiente en el validador, que es lo que el PO intenta lograr aquí. –

Respuesta

67

Así es como se podría obtener otro valor de la propiedad:

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

Genial, esta es solo la respuesta ** ¡Estoy ** buscando! Excepto que mi contexto de validación siempre es nulo. ¿Algunas ideas? –

+2

@GrimmTheOpiner Sé que esto es viejo, pero para cualquiera que esté buscando intente agregar 'public override bool RequiresValidationContext {get {return true; }} 'en' CustomAttribute' – Ryan

+0

@Ryan Wow, ¿por qué quería hacer esto? ¡Incluso si pudiera recordar, ahora tengo dos trabajos más! :-) –

4

favor mire abajo para mi ejemplo:

clase Modelo implementos 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)); 
       } 
      } 
     } 

clase de atributo también contiene evento hendler.

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

Uso

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

Para simplificar código que decidió omitir una validación.

Cuestiones relacionadas