2011-02-08 20 views
31

¿Cómo podría escribir un ValidationAttribute personalizado que compare dos campos? Este es el escenario común de "ingresar contraseña", "confirmar contraseña". Necesito estar seguro de que los dos campos son iguales y para mantener las cosas consistentes, quiero implementar la validación mediante DataAnnotations.Usando DataAnnotations para comparar dos propiedades del modelo

Así que en pseudo-código, estoy buscando una manera de implementar algo como lo siguiente:

public class SignUpModel 
{ 
    [Required] 
    [Display(Name = "Password")] 
    public string Password { get; set; } 

    [Required] 
    [Display(Name = "Re-type Password")] 
    [Compare(CompareField = Password, ErrorMessage = "Passwords do not match")] 
    public string PasswordConfirm { get; set; } 
} 

public class CompareAttribute : ValidationAttribute 
{ 
    public CompareAttribute(object propertyToCompare) 
    { 
     // ?? 
    } 

    public override bool IsValid(object value) 
    { 
     // ?? 
    } 
} 

Entonces la pregunta es, ¿cómo codificar los [Comparar] ValidationAttribute?

Respuesta

25

Existe una CompareAttribute en el Framework ASP.NET MVC 3 que hace esto. Si está utilizando ASP.NET MVC 2 y apuntando a .Net 4.0, entonces podría ver la implementación en el código fuente de ASP.NET MVC 3.

3

Puede tener un atributo de validación personalizado y aplicarlo en el modelo y no en propiedades individuales. Aquí hay un example que puede ver.

7

Esta es una versión más larga de la respuesta de Darin:

public class CustomAttribute : ValidationAttribute 
{  
    public override bool IsValid(object value) 
    { 
     if (value.GetType() == typeof(Foo)) 
     { 
      Foo bar = (Foo)value; 
      //compare the properties and return the result 
     } 

     throw new InvalidOperationException("This attribute is only valid for Foo objects"); 
    } 
} 

y uso:

[MetadataType(typeof(FooMD))] 
public partial class Foo 
{ 
    ... functions ... 
} 

[Custom] 
public class FooMD 
{ 
    ... other data annotations ... 
} 

El error se mostrará en @Html.ValidationSummary(false)

42

Asegúrese de que las referencias del proyecto system.web. mvc v3.xxxxx.

A continuación, el código debe ser algo como esto:

using System.Web.Mvc; 

. . . .

[Required(ErrorMessage = "This field is required.")]  
public string NewPassword { get; set; } 

[Required(ErrorMessage = "This field is required.")] 
[Compare(nameof(NewPassword), ErrorMessage = "Passwords don't match.")] 
public string RepeatPassword { get; set; } 
+2

En este caso, puede ahorrarse el atributo requerido para la segunda propiedad puesto que ya están haciendo cumplir una comparación con la primera propiedad que es de hecho requerida. –

+1

Tenga en cuenta que, a partir de C# 6.0, ahora es posible utilizar la palabra clave 'nameof', en lugar de utilizar" cadenas mágicas "como nombres de propiedad.Esto permite una refactorización mejor/más fácil de cualquier propiedad relacionada, ya que usa el nombre de propiedad fuertemente tipado (y le ahorra tener que recordar actualizar la cadena mágica (como he hecho algunas veces)). Además, el compilador cometerá un error si alguna vez se le pasó, de alguna manera, haciéndolo "infalible". Ejemplo de uso según la respuesta de @Janx: '[CompareAttribute (nameof (NewPassword), ErrorMessage =" Las contraseñas no coinciden. ")]' –

0

Para las personas que buscan futuros en este tema, yo estaba tratando de escribir un atributo de validación que podría evaluar una expresión regular si la propiedad de un objeto fuera un cierto valor. En mi caso, si una dirección era una dirección de envío, que no quería apartados de correos habilitado, así que esto es lo que ocurrió:

Uso

[Required] 
public EAddressType addressType { get; set; } //Evaluate Validation attribute against this 

[EvaluateRegexIfPropEqualsValue(Constants.NOT_PO_BOX_REGEX, "addressType", EAddressType.Shipping, ErrorMessage = "Unable to ship to PO Boxes or APO addresses")] 
public String addressLine1 { get; set; } 

Y aquí está el código para el atributo de validación :

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)] 
public class EvaluateRegexIfPropEqualsValue : ValidationAttribute 
{ 
    Regex _regex; 
    string _prop; 
    object _targetValue; 

    public EvaluateRegexIfPropEqualsValue(string regex, string prop, object value) 
    { 
     this._regex = new Regex(regex); 
     this._prop = prop; 
     this._targetValue = value; 
    } 

    bool PropertyContainsValue(Object obj) 
    { 
     var propertyInfo = obj.GetType().GetProperty(this._prop); 
     return (propertyInfo != null && this._targetValue.Equals(propertyInfo.GetValue(obj, null))); 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext obj) 
    { 
     if (this.PropertyContainsValue(obj.ObjectInstance) && value != null && !this._regex.IsMatch(value.ToString())) 
     { 
      return new ValidationResult(this.ErrorMessage); 
     } 
     return ValidationResult.Success; 
    } 
} 
2

si ustedes están utilizando MVC 4 por favor probar este código .. que va a resolver su error ..

haga por favor un Metadataclass que en la clase parcial impliment comfirmemail p roperties. verifique el código a continuación para más detalles.

using System; 
    using System.Collections.Generic; 
    using System.ComponentModel.DataAnnotations; 
    using StringlenghtMVC.Comman; 
    using System.Web.Mvc; 

using System.Collections; 

    [MetadataType(typeof(EmployeeMetaData))] //here we call metadeta class 
    public partial class Employee 
    { 
     public int Id { get; set; } 
     public string Name { get; set; } 
     public string Email { get; set; } 
     public Nullable<int> Age { get; set; } 
     public string Gender { get; set; } 
     public Nullable<System.DateTime> HireDate { get; set; } 

     //[CompareAttribute("Email")] 
     public string ConfirmEmail { get; set; } 
    } 

    public class EmployeeMetaData 
    { 
     [StringLength(10, MinimumLength = 5)] 
     [Required] 
     //[RegularExpression(@"(([A-za-Z]+[\s]{1}[A-za-z]+))$", ErrorMessage = "Please enter Valid Name")] 
     public string Name { get; set; } 

     [Range(1, 100)] 
     public int Age { get; set; } 
     [CurrentDate] 
     [DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)] 
     public DateTime HireDate { get; set; } 

     //[RegularExpression(@"^[\w-\._\%][email protected](?:[\w]{2,6}$")] 
     public string Email { get; set; } 

     [System.Web.Mvc.CompareAttribute("Email")] 
     public string ConfirmEmail { get; set; } 


    }