【问题标题】:Custom Validation Attribute MVC2自定义验证属性 MVC2
【发布时间】:2010-11-06 18:47:45
【问题描述】:

我有一个自定义验证属性,用于检查两个属性是否具有相同的值(例如密码和重新输入密码):

[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); 返回 null。谁能帮我理解为什么会这样?

【问题讨论】:

  • Object value 被传递到 IsValid 方法中的是什么?看起来无论该对象是什么,它都没有密码属性
  • 附带说明,MVC 3 有一个 CompareAttribute 可以完全满足您的要求。 我正在使用 MVC 3 rc - 比较不起作用 - 找不到类型或命名空间...?
  • CompareAttribute 位于 System.Web.Mvc 中,而 RequiredAttribute、StringLengthAttribute、... 位于 System.ComponentModel.DataAnnotations 中。

标签: c# asp.net asp.net-mvc-2 data-annotations


【解决方案1】:

因为IsValid()object value参数不是整个模型,而只是你的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; }

    // ...
}

【讨论】:

  • 那个框架 - 这么多的内置属性,这么少的时间。 :)
  • 其实用在默认的ASP.NET MVC 2项目模板中。而且不是框架的一部分。
  • 这真的很有帮助。我最终使用了这里建议的方法blog.ceredir.com/index.php/2010/08/10/… 这样我就可以在我的字段旁边显示验证消息
【解决方案2】:

我不知道为什么你的代码不起作用,但是通过GetType()你可以得到预期的结果:

var property = value.GetType().GetProperty(CompareProperty);
var comparePropertyValue = property.GetValue(value, null).ToString();

【讨论】:

    【解决方案3】:

    根据http://msdn.microsoft.com/en-us/library/ybh0y4fd.aspx TypeDecroptor.GetProperties “返回指定组件的属性集合。”它还继续说:

    组件的属性可以不同于类的属性, 因为如果组件被选址,站点可以添加或删除属性。

    所以在我看来,这并不是获取类属性的正确方法。我认为@Pieter 的方法更符合您的需求。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-15
      • 1970-01-01
      • 2013-01-17
      • 1970-01-01
      • 2011-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多