Designing Custom Validation Attributes
In this lesson, we will learn code a custom validation attribute that will perform both server-side and client-side validation.
A custom validation attribute can be implemented by inheriting from the ValidationAttribute
class. Server-side validation code is provided by overriding the methods that perform validation and error message formatting.
Client-side validation requires that our attribute implements the IClientModelValidator
interface whose unique AddValidation
method specifies the data-
attributes to add to the input field. The actual client-side validation code must be provided through a JavaScript validator which is connected to the parser that processes all data-
attributes through a JavaScript adapter.
We will describe all the above steps while implementing an example custom validation attribute: the ExtensionAttribute
.
The ExtensionAttribute
As an example, we will define an attribute that checks the extension of a Web Address. It is useful when combined with the UrlAttribute
to force the user to insert the address of a pdf, or of a supported image type. The basic idea is to pass it a string with all comma-separated allowed extensions. Something like .jpg
,.jpeg
, or .png
. The usage should be similar to the example below:
[Display(Name="URL of picture"), Url, Extension(".jpg,.jpeg,.png")]public string WebPicture { get; set; }
The combined usage of both UrlAttribute
and ExtensionAttribute
forces the user to insert the Web Address of an image.
Server-side validation
Custom attributes can be inserted in a folder called Validation
that is placed in the application root. There, we can add an ExtensionAttribute
class that inherits from ValidationAttribute
:
using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations;using System.Linq;using System.Threading.Tasks;namespace MvcProject.ViewModels{public class ExtensionAttribute: ValidationAttribute, IClientModelValidator{private const string defaultMessage = "{0} is not a a supported image addrees";private string extensions;public ExtensionAttribute(string extensions){this.extensions = extensions;}private string extensions;public ExtensionAttribute(string extensions){this.extensions = extensions;}public override bool IsValid(object value){...}}}
The default namespace name has been changed to match the namespace of all ViewModels, so we don’t need any
using
to use it with our ViewModels. However, we can also use a dedicated namespace.
The comma-separated list of extensions passed to the ...