自定义validation属性MVC2

我有一个自定义validation属性,它检查两个属性是否具有相同的值(如密码和重新键入密码):

[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 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。 任何人都可以帮助我理解为什么会这样吗?

因为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; } // ... } 

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

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

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

组件的属性可能与类的属性不同,因为如果组件位于该组件,则该站点可以添加或删除属性。

所以在我看来,这不是用于获取类属性的正确方法。 我认为@ Pieter的方法更像是你真正想要的。