Использование DataAnnotations для сравнения двух свойств модели

Как мне написать собственный атрибут ValidationAttribute, который сравнивает два поля? Это обычный сценарий «введите пароль» и «подтвердите пароль». Мне нужно убедиться, что эти два поля равны, и для согласованности я хочу реализовать проверку через DataAnnotations.

Итак, в псевдокоде я ищу способ реализовать что-то вроде следующего:

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

Итак, вопрос в том, как мне закодировать атрибут [Compare] ValidationAttribute?


person Scott    schedule 08.02.2011    source источник


Ответы (6)


В ASP.NET MVC 3 Framework есть атрибут CompareAttribute, который делает это. Если вы используете ASP.NET MVC 2 и ориентируетесь на .Net 4.0, вы можете посмотреть на реализацию в исходном коде ASP.NET MVC 3.

person Joe Cartano    schedule 08.02.2011

Убедитесь, что ваш проект ссылается на system.web.mvc v3.xxxxx.

Тогда ваш код должен быть примерно таким:

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; }
person Janx from Venezuela    schedule 12.01.2012
comment
В этом случае вы можете сохранить атрибут Required для второго свойства, поскольку вы уже выполняете сравнение с первым свойством, которое на самом деле является обязательным. - person Pepito Fernandez; 07.12.2012
comment
Обратите внимание, что, начиная с C # 6.0, теперь можно использовать ключевое слово nameof вместо использования магических строк в качестве имен свойств. Это упрощает / улучшает рефакторинг любых связанных свойств, поскольку вместо этого использует строго типизированное имя свойства (и избавляет вас от необходимости не забывать обновлять волшебную строку (как я делал несколько раз)). Кроме того, компилятор выдаст ошибку, если вы когда-нибудь что-то пропустили, что сделает его надежным. Пример использования согласно ответу @ Janx: [CompareAttribute(nameof(NewPassword), ErrorMessage = "Passwords don't match.")] - person Geoff James; 18.07.2016

Это более длинная версия ответа Дарина:

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

и использование:

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

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

Ошибка отобразится в @Html.ValidationSummary(false)

person AndyMcKenna    schedule 09.11.2011

Вы можете иметь настраиваемый атрибут проверки и применять его к модели, а не к отдельным свойствам. Вот пример, на который вы можете взглянуть.

person Darin Dimitrov    schedule 08.02.2011

Для будущих людей, рассматривающих эту проблему, я пытался написать атрибут проверки, который оценивал бы регулярное выражение, если бы свойство объекта было определенным значением. В моем случае, если адрес был адресом доставки, я не хотел, чтобы почтовые ящики были включены, поэтому вот что я придумал:

использование

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

А вот код для атрибута проверки:

[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;
    }
}
person Daniel    schedule 04.11.2014

если вы, ребята, используете MVC 4, попробуйте этот код .. он решит вашу ошибку ..

пожалуйста, сделайте один метадатакласс, чем в частичном классе, имплементируйте свойства comfirmemail. проверьте приведенный ниже код для получения более подробной информации.

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


    }
person Snehal Thakkar    schedule 15.04.2016