Пользовательский атрибут проверки MVC2 - PullRequest
8 голосов
/ 06 ноября 2010

У меня есть пользовательский атрибут проверки, который проверяет, имеют ли два свойства одинаковые значения или нет (например, пароль и пароль повторного ввода):

[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false)]
    public class EqualToPropertyAttribute : ValidationAttribute
    {
        public string CompareProperty { get; set; }

        public EqualToPropertyAttribute(string compareProperty)
        {
            CompareProperty = compareProperty;
            ErrorMessage = string.Format(Messages.EqualToError, compareProperty);
        }

        public override bool IsValid(object value)
        {
            if (value == null)
            {
                return true;
            }
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
            var property = properties.Find(CompareProperty, true);
            var comparePropertyValue = property.GetValue(value).ToString();

            return comparePropertyValue == value.ToString();
        }
    }

У меня есть класс модели представления, в котором есть все полядля формы регистрации следующим образом:

public class SignUpViewModel
    {
        [Required]
        [StringLength(100)]
        public string Username { get; set; }

        [Required]
        [Password]
        public string Password { get; set; }

        [Required]
        [DisplayText("RetypePassword")]
        [EqualToProperty("Password")]
        public string RetypePassword { get; set; }

        [Required]
        [StringLength(50)]
        [DisplayText("FirstName")]
        public string FirstName { get; set; }

        [Required]
        [StringLength(100)]
        [DisplayText("LastName")]
        public string LastName { get; set; }

        [Required]
        [DisplayText("SecurityQuestion")]
        public int SecurityQuestionID { get; set; }

        public IEnumerable<SelectListItem> SecurityQuestions { get; set; }

        [Required]
        [StringLength(50)]
        public string Answer { get; set; }
}

Ниже приведен код моего контроллера:

public virtual ActionResult Index()
    {
        var signUpViewModel = new SignUpViewModel();

        signUpViewModel.SecurityQuestions = new SelectList(questionRepository.GetAll(),"SecurityQuestionID", "Question");
        return View(signUpViewModel);
    }

        [HttpPost]
        public virtual ActionResult Index(SignUpViewModel viewModel)
        {
            // Code to save values to database
        }

Когда я ввожу значения формы и нажимаю, отправьте строку кода, которая пытается получить свойстводескриптор var property = properties.Find (CompareProperty, true); возвращает ноль.Может кто-нибудь помочь мне понять, почему это происходит?

Ответы [ 3 ]

13 голосов
/ 06 ноября 2010

Поскольку object value параметр IsValid() - это не вся модель, а только ваша string RetypePassword.

Это должен быть атрибут, который влияет на весь объект модели, а не толькосвойство.

Хотя я бы предложил вам использовать PropertiesMustMatchAttribute.

[PropertiesMustMatch("Password", "RetypePassword", 
  ErrorMessage = "The password and confirmation password do not match.")]
public class SignUpViewModel
{
   [Required]
   [StringLength(100)]
   public string Username { get; set; }

   [Required]
   [Password]
   public string Password { get; set; }

   [Required]
   [DisplayText("RetypePassword")]
   public string RetypePassword { get; set; }

   //...
}

Редактировать

Этот атрибут на самом деле не является частью ASP.NETИнфраструктура MVC2, но определенная в шаблоне проекта MVC 2 по умолчанию.

[AttributeUsage( AttributeTargets.Class, AllowMultiple = true, Inherited = true )]
public sealed class PropertiesMustMatchAttribute : ValidationAttribute {
    private const string _defaultErrorMessage = "'{0}' and '{1}' do not match.";
    private readonly object _typeId = new object();

    public PropertiesMustMatchAttribute( string originalProperty, string confirmProperty )
        : base( _defaultErrorMessage ) {
        OriginalProperty = originalProperty;
        ConfirmProperty = confirmProperty;
    }

    public string ConfirmProperty { get; private set; }
    public string OriginalProperty { get; private set; }

    public override object TypeId {
        get {
            return _typeId;
        }
    }

    public override string FormatErrorMessage( string name ) {
        return String.Format( CultureInfo.CurrentUICulture, ErrorMessageString,
            OriginalProperty, ConfirmProperty );
    }

    public override bool IsValid( object value ) {
        PropertyDescriptorCollection properties = TypeDescriptor.GetProperties( value );
        object originalValue = properties.Find( OriginalProperty, true /* ignoreCase */).GetValue( value );
        object confirmValue = properties.Find( ConfirmProperty, true /* ignoreCase */).GetValue( value );
        return Object.Equals( originalValue, confirmValue );
    }
}

В дополнение к этому, MVC 3 имеет CompareAttribute, который выполняет именно то, что вам нужно.

public class SignUpViewModel
{
    [Required]
    [StringLength(100)]
    public string Username { get; set; }

    [Required]
    [Password]
    public string Password { get; set; }

    [Required]
    [DisplayText("RetypePassword")]
    [Compare("Password")] // the RetypePassword property must match the Password field in order to be valid.
    public string RetypePassword { get; set; }

    // ...
}
0 голосов
/ 06 ноября 2010

Согласно http://msdn.microsoft.com/en-us/library/ybh0y4fd.aspx TypeDescroptor.GetProperties «Возвращает коллекцию свойств для указанного компонента .»далее также говорится:

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

Так что мне кажется, что это не тот метод, который нужно использовать для получения свойств класса.Я думаю, что метод @ Питера - это больше, чем вы действительно ищете.

0 голосов
/ 06 ноября 2010

Я не уверен, почему ваш код не работает, но через GetType() вы можете получить ожидаемый результат:

var property = value.GetType().GetProperty(CompareProperty);
var comparePropertyValue = property.GetValue(value, null).ToString();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...