2011-02-08 12 views
31

Jak mam napisać niestandardową ValidationAttribute, która porównuje dwa pola? Jest to typowy scenariusz "Wprowadź hasło", "Potwierdź hasło". Muszę mieć pewność, że te dwa pola są równe i aby zachować spójność, chcę zaimplementować walidację za pomocą DataAnnotations.Używanie DataAnnotations do porównywania dwóch właściwości modelu

Więc w pseudo-kodzie, szukam sposobu, aby zaimplementować coś podobnego do poniższego:

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) 
    { 
     // ?? 
    } 
} 

Więc pytanie brzmi, jak mogę Kodeksu [por] ValidationAttribute?

Odpowiedz

25

W module ASP.NET MVC 3 występuje funkcja CompareAttribute. Jeśli korzystasz z ASP.NET MVC 2 i kierowania na .Net 4.0, możesz spojrzeć na implementację w kodzie źródłowym ASP.NET MVC 3.

3

Możesz mieć niestandardowy atrybut sprawdzania poprawności i zastosować go w modelu, a nie w poszczególnych właściwościach. Oto example, na które możesz rzucić okiem.

7

Jest to dłuższa wersja odpowiedzi Darin za:

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

i użytkowanie:

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

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

Błąd zostanie wyświetlony w @Html.ValidationSummary(false)

42

upewnić się, że projekt odwołuje System.Web. mvc v3.xxxxx.

Potem kod powinien być mniej więcej tak:

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

W tym przypadku można zapisać sam atrybut Wymagana dla drugiej właściwości, ponieważ już wymuszasz porównanie z pierwszą właściwością, która w rzeczywistości jest wymagana. –

+1

Należy zauważyć, że od wersji C# 6.0 można teraz używać słowa kluczowego 'nameof', zamiast używać" ciągów magicznych "jako nazw właściwości.Pozwala to na lepsze/łatwiejsze refaktoryzowanie dowolnych powiązanych właściwości, ponieważ zamiast tego używa nazwy mocno wpisanej właściwości (i oszczędza konieczność pamiętania, aby zaktualizować magiczny ciąg znaków (tak jak zrobiłem to kilka razy)). Dodatkowo, kompilator popełni błąd, jeśli kiedykolwiek opuścisz go, w jakiś sposób - czyniąc go "niezawodny". Przykład użycia jak na odpowiedź @ Janx: '[CompareAttribute (nameof (NewPassword), ErrorMessage =" Hasła nie pasują. ")]' –

0

Dla przyszłych osób zainteresowanych tą kwestią próbowałem napisać atrybut sprawdzania poprawności, który oceniłby wyrażenie regularne, gdyby właściwość obiektu miała określoną wartość. W moim przypadku, gdy adres był adres wysyłki, nie chciałem być włączona PO Boxes, więc to, co wymyśliłem:

Wykorzystanie

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

A oto kod dla atrybutu walidacji :

[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

jeśli faceci są z wykorzystaniem MVC 4 spróbuj tego kodu .. będzie rozwiązać swój błąd ..

należy wykonać jedną Metadataclass niż w częściowej klasy impliment comfirmemail p właściwości. sprawdź poniższy kod, aby uzyskać więcej informacji.

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


    } 
Powiązane problemy