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(A
Because the object value
parameter of IsValid()
is not the entire model, but just your 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
.
[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; }
//...
}
That attribute is actually not part of the ASP.NET MVC2 framework, but defined in the default MVC 2 project template.
[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.
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; }
// ...
}
According to http://msdn.microsoft.com/en-us/library/ybh0y4fd.aspx the TypeDescroptor.GetProperties "Returns the collection of properties for a specified component." 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.
I'm not sure why your code doesn't work, but through GetType()
you can get the expected result:
var property = value.GetType().GetProperty(CompareProperty);
var comparePropertyValue = property.GetValue(value, null).ToString();