Search code examples
c#asp.netvalidationasp.net-coreasp.net-core-mvc

ASP.Net Core MVC - Client-side validation for custom attribute


In previous versions of the MVC framework custom validation would be achieved through implementing IClientValidatable and the GetClientValidationRules method.

However in ASP.Net Core MVC we do not have this interface, although we do have IClientModelValidator which a defining a very similar method. The implementation of which never gets called however.

So - how do we implement client-side validation for a custom attribute in ASP.NET Core MVC?


Solution

  • The IClientModelValidator is in fact the right interface. I've made a contrived sample implementation below.

    Attribute

    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
    public sealed class CannotBeRedAttribute : ValidationAttribute, IClientModelValidator
    {
        public override bool IsValid(object value)
        {
            var message = value as string;
            return message?.ToUpper() == "RED";
        }
    
        public void AddValidation(ClientModelValidationContext context)
        {
            MergeAttribute(context.Attributes, "data-val", "true");
            var errorMessage = FormatErrorMessage(context.ModelMetadata.GetDisplayName());
            MergeAttribute(context.Attributes, "data-val-cannotbered", errorMessage);
        }
    
        private bool MergeAttribute(
            IDictionary<string, string> attributes,
            string key,
            string value)
        {
            if (attributes.ContainsKey(key))
            {
                return false;
            }
            attributes.Add(key, value);
            return true;
        }
    }
    

    Model

    public class ContactModel
    {
        [CannotBeRed(ErrorMessage = "Red is not allowed!")]
        public string Message { get; set; }
    }
    

    View

    @model WebApplication.Models.ContactModel
    
    <form asp-action="Contact" method="post">
        <label asp-for="Message"></label>
        <input asp-for="Message" />
        <span asp-validation-for="Message"></span>
        <input type="submit" value="Save" />
    </form>
    
    @section scripts {
        <script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
        <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
        <script>
            $.validator.addMethod("cannotbered",
                function (value, element, parameters) {
                    return value.toUpperCase() !== "RED";
                });
    
            $.validator.unobtrusive.adapters.add("cannotbered", [], function (options) {
                options.rules.cannotbered = {};
                options.messages["cannotbered"] = options.message;
            });
        </script>
    }