Reputation: 398
I have a compare validation for a password - confirm password fields and also a server validation to check if the password fits with a minimum number of characters.
View:
@Html.PasswordFor(model => model.password)
@Html.PasswordFor(model => model.repeatPassword)
Model:
public class Model_Clerk
{
public int clerkID { get; set; }
public string password { get; set; }
[Compare("password", ErrorMessage = "Error comparing password and password confirm values")]
public string repeatPassword { get; set; }
}
Controller action method:
public ActionResult SaveClerk(Model_Clerk model)
{
//Password minimum lenght
if (!string.IsNullOrEmpty(model.password) && model.password.Trim().Length < 5)
{
ModelState.AddModelError(model.password, "Password must be at least 5 characters long");
}
if (ModelState.IsValid)
{
//Save logic here...
}
else
{
return PartialView("EditClerks", model);
}
}
When the server validation is executed the warning message appears correctly, and after that the compare validation will not work anymore. Any idea?
Upvotes: 1
Views: 3578
Reputation: 96
Ran across this issue today and wrote a CompareIf
custom attribute. It's nearly identical to RequiredIf
(covered here), but inherits CompareAttribute
instead and accepts the otherProperty
as a third argument.
using System.ComponentModel.DataAnnotations;
public class CompareIfAttribute : CompareAttribute
{
private readonly string _dependentProperty;
private readonly object _targetValue;
public CompareIfAttribute(string dependentProperty, object targetValue, string otherProperty) : base(otherProperty)
{
_dependentProperty = dependentProperty;
_targetValue = targetValue;
}
/// <summary>
/// Returns if the given validation result is valid. It checks if the RequiredIfAttribute needs to be validated
/// </summary>
/// <param name="value">Value of the control</param>
/// <param name="validationContext">Validation context</param>
/// <returns></returns>
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var field = validationContext.ObjectType.GetProperty(_dependentProperty);
if (field != null)
{
var dependentValue = field.GetValue(validationContext.ObjectInstance, null);
if (dependentValue == null && _targetValue == null || dependentValue?.ToString() == _targetValue?.ToString())
{
var test = base.IsValid(value, validationContext);
if (test != ValidationResult.Success)
{
return test;
}
}
return ValidationResult.Success;
}
throw new ValidationException($"CompareIf Dependant Property {_dependentProperty} does not exist");
}
}
First two arguments are the dependent property and target value, and the third is the property to compare with. Usage:
public bool CandidateHasNoLegalMiddleName { get; set; }
public string CandidateMiddle { get; set; }
[CompareIf(nameof(CandidateHasNoLegalMiddleName), false, nameof(CandidateMiddle)]
public string ConfirmMiddle { get; set; }
This will allow the comparison to occur only if the condition is true.
Upvotes: 0
Reputation: 20364
From our comments, I think that actually the best solution would be to write your own DataAnnotation.
Something like [CompareIf("password", ErrorMessage = "Error comparing password and password confirm values")]
Your DataAnnotation Code would have to check to see if the Password is not empty and valid, and then compare the two values.
Upvotes: 1