web-dev-qa-db-fra.com

Utilisation de DataAnnotations pour comparer deux propriétés de modèle

Comment pourrais-je écrire un attribut de validation personnalisé qui compare deux champs? Il s'agit du scénario courant "saisir le mot de passe", "confirmer le mot de passe". Je dois être sûr que les deux champs sont égaux et pour garder les choses cohérentes, je veux implémenter la validation via DataAnnotations.

Donc, dans le pseudo-code, je cherche un moyen d'implémenter quelque chose comme ceci:

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

La question est donc de savoir comment coder l'attribut [Compare] ValidationAttribute?

38
Scott

Il existe un CompareAttribute dans le framework ASP.NET MVC 3 qui fait cela. Si vous utilisez ASP.NET MVC 2 et que vous ciblez .Net 4.0, vous pouvez consulter l'implémentation dans le code source ASP.NET MVC 3.

30
Joe Cartano

Assurez-vous que votre projet fait référence à system.web.mvc v3.xxxxx.

Ensuite, votre code devrait ressembler à ceci:

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; }
58
Janx from Venezuela

Voici une version plus longue de la réponse 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");
    }
}

et utilisation:

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

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

L'erreur s'affichera dans @Html.ValidationSummary(false)

7
AndyMcKenna

Vous pouvez avoir un attribut de validation personnalisé et l'appliquer sur le modèle et non sur des propriétés individuelles. Voici un exemple que vous pourriez consulter.

3
Darin Dimitrov

si vous utilisez MVC 4, essayez ce code .. il résoudra votre erreur ..

veuillez faire un Metadataclass que dans les propriétés de comfirmemail de classe d'implémentation de classe partielle. vérifiez le code ci-dessous pour plus de détails.

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-\._\%]+@(?:[\w]{2,6}$")]
        public string Email { get; set; }

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


    }
2
Snehal Thakkar

Pour les futures personnes regardant ce problème, j'essayais d'écrire un attribut de validation qui évaluerait une expression régulière si la propriété d'un objet avait une certaine valeur. Dans mon cas, si une adresse était une adresse de livraison, je ne voulais pas que les boîtes postales soient activées, alors voici ce que j'ai trouvé:

Usage

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

Et voici le code de l'attribut de validation:

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