I have created a custom validator this way:
public class IntArrayRequiredAttribute : ValidationAttribute
{
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if ((!(value is int[] array) || !array.Any() || array.Any(item => item == 0)))
return new ValidationResult(this.ErrorMessage);
return ValidationResult.Success;
}
}
and apply it to a model property:
[IntArrayRequiredAttribute(ErrorMessage = "You must select {0}.")]
[Display(Name = "Rol")]
public int[] Roles { get; set; }
Well, when the validation fails, this error is shown:
"You must select {0}."
How can I return the error message so that {0} is replaced by the display name of the field automatically, such as the built-in validators?
Expected result should be "You must select Rol."
EDIT:
By Seeing ValidationAttribute source code, I read:
public ValidationResult GetValidationResult(object value, ValidationContext validationContext) {
if (validationContext == null) {
throw new ArgumentNullException("validationContext");
}
ValidationResult result = this.IsValid(value, validationContext);
// If validation fails, we want to ensure we have a ValidationResult that guarantees it has an ErrorMessage
if (result != null) {
bool hasErrorMessage = (result != null) ? !string.IsNullOrEmpty(result.ErrorMessage) : false;
if (!hasErrorMessage) {
string errorMessage = this.FormatErrorMessage(validationContext.DisplayName);
result = new ValidationResult(errorMessage, result.MemberNames);
}
}
return result;
}
I saw that it calls my overridden IsValid method and it formats the message. Why isn't it formatting in my case?
If I use the IsValid overload, it formats correctly, however, I need to use this method because I need validationContext for other validation purpose.
I don't think the reference source match the real code, as reflection revеаls:
public ValidationResult GetValidationResult(object value, ValidationContext validationContext)
{
if (validationContext == null)
{
throw new ArgumentNullException("validationContext");
}
ValidationResult validationResult = IsValid(value, validationContext);
if (validationResult != null && (validationResult == null || string.IsNullOrEmpty(validationResult.ErrorMessage)))
{
string errorMessage = FormatErrorMessage(validationContext.DisplayName);
validationResult = new ValidationResult(errorMessage, validationResult.MemberNames);
}
return validationResult;
}
So if you want to fit everything into the single overload
protected override ValidationResult IsValid(object value, ValidationContext validationContext) {...}
you could let the base class do the ErrorMessage formatting:
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if ((!(value is int[] array) || !array.Any() || array.Any(item => item == 0)))
{
return new ValidationResult(null);
}
return ValidationResult.Success;
}
or you could do the formatting yourself:
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if ((!(value is int[] array) || !array.Any() || array.Any(item => item == 0)))
{
string errorMessage = FormatErrorMessage(validationContext.DisplayName);
return new ValidationResult(errorMessage);
}
return ValidationResult.Success;
}