I'm developing an ASP.NET MVC 5.2.3 custom data annotation for validation in Visual Studio 2015. It needs to take any number of fields and ensure that if one has a value, they all must have a value; if they're all null/blank, it should be okay.
A few examples have helped:
- ASP.NET MVC implement custom validator use IClientValidatable
- MVC Form Validation on Multiple Fields
- http://www.macaalay.com/2014/02/24/unobtrusive-client-and-server-side-age-validation-in-mvc-using-custom-data-annotations/
However, I'm not sure how to do the client-side validation where you have an unknown number of fields being validated.
How do you pass that to the client using the implementation of the GetClientValidationRules()
method of the IClientValidatable
interface?
Also, how do I apply this new data annotation to the properties on my view model? Would it look like this?
[MultipleRequired("AppNumber", "UserId", /* more fields */), ErrorMessage = "Something..."]
[DisplayName("App #")]
public int AppNumber { get; set; }
[DisplayName("User ID")]
public int UserId { get; set; }
Here's as far as I could get with the MultipleRequiredAttribute
custom data annotation class:
public class MultipleRequiredAttribute : ValidationAttribute, IClientValidatable
{
private readonly string[] _fields;
public MultipleRequiredAttribute(params string[] fields)
{
_fields = fields;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
// If any field has value, then all must have value
var anyHasValue = _fields.Any(f => !string.IsNullOrEmpty(f));
if (!anyHasValue) return null;
foreach (var field in _fields)
{
var property = validationContext.ObjectType.GetProperty(field);
if (property == null)
return new ValidationResult($"Property '{field}' is undefined.");
var fieldValue = property.GetValue(validationContext.ObjectInstance, null);
if (string.IsNullOrEmpty(fieldValue?.ToString()))
return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
}
return null;
}
public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
{
yield return new ModelClientValidationRule
{
ErrorMessage = ErrorMessage,
ValidationType = "multiplerequired"
};
}
}
Thank you.
GetClientValidationRules()
method, you add aModelClientValidationRule
where you can pass a (say) comma separated list of the property names - i.e. yourfields
values - which can be parsed and used in the client side scripts (if your having issues, let me know and I'll add an answer but wont get a chance for a few hours) – user3559349return new ValidationResult($"Property '{field}' is undefined.");
does not really makes sense (displaying that message in the view would be meaningless and confusing to the user) - either ignore it, or check in in the constructor and throw an exception – user3559349