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. ...