Custom Validation Attribute in MVC

Creating a custom validation attribute for that you can use as a Data Annotation on your models is not hard, but does require a bit of care to make it work on both the server and client side. The first step is to create a class that inherits from ValidationAttribute and implements IClientValidatable. In one project, we need to validate against US and UK phone numbers.

    [AttributeUsage(AttributeTargets.Property | 
    AttributeTargets.Field | 
    AttributeTargets.Parameter, AllowMultiple = false)]
    public class ValidPhoneAttribute : ValidationAttribute, IClientValidatable

From there, we implement the IsValid method:

        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            ValidationResult validationResult = ValidationResult.Success;
            string toValidate = (string)value;
            if (!Parse.IsPhone(toValidate))
            {
                validationResult = new ValidationResult(ErrorMessageString);
            }

            return validationResult;
        }

Finally, we implement IClientValidate. The "validphone" string defines the function in our javascript file that will be called.

        public IEnumerable GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
        {
            string errorMessage = ErrorMessageString;

            // The value we set here are needed by the jQuery adapter
            ModelClientValidationRule validPhoneRule = new ModelClientValidationRule()
            {
                ErrorMessage = errorMessage,
                ValidationType = "validphone" /* This is the name the jQuery adapter will use*/
            };


            yield return validPhoneRule;
        }

In our javascript library file custom-validation.js, we added

$.validator.addMethod("validphone", function (value, element, params) {
    usPhoneRe = /^[(]?(\d{3})[) -\.]?[ ]?(\d{3})[ -\.]?(\d{4})$/;
    ukPhoneRe = /^\+?44[ -\(\)\d]{9,}$/;

    var isUsPhone;
    isUsPhone = usPhoneRe.test(value);

    var isUkPhone;
    isUkPhone = ukPhoneRe.test(value);

    return isUsPhone || isUkPhone;
});

$.validator.unobtrusive.adapters.add("validphone", function (options) {
    options.rules["validphone"] = "#" + options.value;
    options.messages["validphone"] = options.message;
});

This registers the method with the jquery validator object.