简体   繁体   English

自定义验证属性MVC2

[英]Custom Validation Attribute MVC2

I have a custom validation attribute which checks to see if two properties have the same values or not (like password and retype password): 我有一个自定义验证属性,它检查两个属性是否具有相同的值(如密码和重新键入密码):

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

I have a view model class which has all the fields for the signup form as follows: 我有一个视图模型类,其中包含注册表单的所有字段,如下所示:

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

Below is my controller code: 以下是我的控制器代码:

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
        }

When I enter the form values and hit submit the line of code which tries to get the property descriptor var property = properties.Find(CompareProperty, true); 当我输入表单值并点击提交代码行时,尝试获取属性描述符var property = properties.Find(CompareProperty,true); is returning null. 返回null。 Can anyone help me understand why this is happening? 任何人都可以帮助我理解为什么会这样吗?

Because the object value parameter of IsValid() is not the entire model, but just your string RetypePassword . 因为IsValid()object value参数不是整个模型,而只是你的string RetypePassword

It would need to be an attribute that affects the whole model object, and not just a property. 它需要是一个影响整个模型对象的属性,而不仅仅是属性。

Although I would suggest you to use the PropertiesMustMatchAttribute . 虽然我建议你使用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; }

   //...
}

Edit 编辑

That attribute is actually not part of the ASP.NET MVC2 framework, but defined in the default MVC 2 project template. 该属性实际上不是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 );
    }
}

On a side note, MVC 3 has a CompareAttribute that does exactly what you want. 另外,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; }

    // ...
}

I'm not sure why your code doesn't work, but through GetType() you can get the expected result: 我不确定为什么你的代码不起作用,但通过GetType()你可以得到预期的结果:

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

According to http://msdn.microsoft.com/en-us/library/ybh0y4fd.aspx the TypeDescroptor.GetProperties "Returns the collection of properties for a specified component ." 根据http://msdn.microsoft.com/en-us/library/ybh0y4fd.aspx,TypeDescroptor.GetProperties “返回指定组件的属性集合。” it also goes on to say: 它还接着说:

The properties for a component can differ from the properties of a class, because the site can add or remove properties if the component is sited. 组件的属性可能与类的属性不同,因为如果组件所在的位置,站点可以添加或删除属性。

So it appears to me that this isn't really the right method to be using to get the properties of a class. 因此在我看来,这不是用于获取类属性的正确方法。 I think @Pieter's method is more what you're really looking for. 我认为@ Pieter的方法更像是你真正想要的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM