Reputation: 8054
I have a ViewModel used for changing a password, and it uses the Compare
DataAnnotation like so:
[Display(Name = "New Password")]
public string New { get; set; }
[Compare("New")]
[Display(Name = "Confirm Password")]
public string ConfirmPassword { get; set; }
Unfortunately the Compare
attribute does not utilize the Display
attribute of the compared property.
The error message displays as
'Confirm Password' and 'New' do not match.
which you can see uses the comparing property's Display
attribute, but not the compared property's.
I'll also specify that I don't want to use the ErrorMessage
parameter because then I'd be hard-coding the property name rather than simply acquiring it from an existing attribute. I'd like to keep this solution as best-practice as possible.
How can I make the Compare
attribute utiliize the Display
attribute of the compared property?
Upvotes: 1
Views: 1401
Reputation: 21
Maybe too late, but I had the same issue in Asp.Net Core Razor Page Web App, and the easy fix was to make a new InputModel class with the Password and ConfirmPassword properties.Then, bind the form inputs to the InputModel properties.
Like this:
[BindProperty]
public InputModel UserPassword { get; set; }
public class InputModel {
[BindProperty]
[Display(Name = "Contraseña")]
[Required(ErrorMessage = "La contraseña es obligatoria.")]
[RegularExpression("^[a-zA-ZñÑ0-9]+$",ErrorMessage = "Sólo se permiten letras y números.")]
[StringLength(12,ErrorMessage = "La contraseña no debe tener más de 12 caracteres.")]
[MaxLength(12,ErrorMessage = "La contraseña no debe tener más de 12 caracteres.")]
[MinLength(2,ErrorMessage = "La contraseña no debe tener menos de 2 caracteres.")]
public string Password { get; set; }
[BindProperty]
[Display(Name = "Confirmación de Contraseña")]
[Required(ErrorMessage = "La contraseña es obligatoria.")]
[Compare(nameof(Password),ErrorMessage = "La contraseña de confirmación no coincide.")]
public string ConfirmPassword { get; set; }
}
Upvotes: 2
Reputation: 1236
I think that this may be some issue with the Compare attribute, since you can see an OtherDisplayName attribute in its list of properties, and it correctly uses the Display Name for the property it is decorating ("Confirm Password" and not "ConfirmPassword").
One work around I have found is to simply create a new class that inherits from CompareAttribute, like so:
public class CompareWithDisplayName : CompareAttribute
{
public CompareWithDisplayName(string otherProperty) : base(otherProperty)
{
}
}
Then use it on your property:
[Display(Name = "New Password")]
public string New { get; set; }
[Display(Name = "Confirm Password")]
[CompareWithDisplayName("New")]
public string ConfirmPassword { get; set; }
I honestly have no idea why this works. It could be that it is something to do with reflection or the order in which it works out what each property's display attribute is. By creating a custom version of it, perhaps the ordering is changed? Either way, this did the trick for me :)
Edit 2 Sorry, forgot to add the extra part needed for client side validation, which is explained here. You can either add this in your Global.asax.cs file:
DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(CompareWithDisplayName), typeof(CompareAttributeAdapter))
or implement the IClientValidatable interface on the custom attribute. Both of these are shown in the link
Upvotes: 2