Custom Data Annotations or Custom Validation Attributes in MVC

In this article you will learn how to create custom data annotation in MVC. The MVC framework has great extensibility features and because of this we can create our own customized data annotation attributes.

Let's assume we don't want the user to enter /.,!@#$% (we can add more characters anytime so no further changes are needed now) characters or symbols with his name.

To do that we have the following alternatives:

      i) We can usee IValidatableObject

      ii) We can validate the data in a controller action and so on

Both ways given above has some limitations, they can't let us validate data out-of-box for example. With IValidatableObject there is no value (the data entered by the user in the TextBox) parameter passed to validate. With validating the data in the controller action, we can't reuse it throughout the application and much more.

So, here we will create our custom data annotation attribute, like Required, MaxLength(10) that we frequently use. Please note, with MaxLength(10) annotation we can pass a value as a parameter to validate. And also these annotations can be used anywhere in the application.

Here is the image of what we will create.


In the preceding image, you can see I have used [ExcludeChar("/.,!@#$%")], that is nothing but a custom data validation attribute used with the Name property. You can also see, when one is entering any character defined with the parameter of ExcludeChar in the TextBox, it displays a model validation error.

Now follow the steps to create this.

Step 1

Add a class ExcludeChar in the project. As you know, all of the validation annotations (like Required, Range, MaxLength) ultimately derive from the ValidationAttributebase class. So we will derive the ExcludeChar class as well.

  1. public class ExcludeChar : ValidationAttribute  
  2. {  
  3.     ....  
  4. } 

Step 2

To implement custom validation logic, we need to override one of the IsValid methods provided by the base class. The IsValid method takes two parameters, the first one is a ValidationContext that gives access to the model type, model object instance, and friendly display name of the property you are validating, among other pieces of information. The second is the value of Object type that is nothing but the information or string typed by the user in the TextBox.

  1. public class ExcludeChar : ValidationAttribute  
  2. {  
  3.     protected override ValidationResult IsValid(object value, ValidationContext validationContext)  
  4.     {  
  5.         ....  
  6.         return ValidationResult.Success;  
  7.     }  
  8. } 

If the value is valid then we can return a successful validation result, but before we can determine if the value is valid, we'll need to know if there a matching character from the set of /.,!@#$%.

Step 3

So far we have the value typed by the user in the IsValid method but we don't have the list of characters (/.,!@#$%). We can do this by adding a constructor to the ExcludeChar class, this constructor will accept a string that is the set of characters (/.,!@#$%), this string will be initialized to a local private variable _chars. Also, the constructor will assign the default error message to the base class.

  1. public class ExcludeChar : ValidationAttribute  
  2. {  
  3.     private readonly string _chars;  
  4.     public ExcludeChar(string chars)  
  5.         : base("{0} contains invalid character.")  
  6.     {  
  7.         _chars = chars;  
  8.     }  
  9.     protected override ValidationResult IsValid(object value, ValidationContext validationContext)  
  10.     {  
  11.         ....  
  12.         return ValidationResult.Success;  
  13.     }  
  14. } 

Step 4

Now the last thing is to implement the validation logic to catch an error:

  1. public class ExcludeChar : ValidationAttribute  
  2. {  
  3.     private readonly string _chars;  
  4.     public ExcludeChar(string chars)  
  5.         : base("{0} contains invalid character.")  
  6.     {  
  7.         _chars = chars;  
  8.     }  
  9.     protected override ValidationResult IsValid(object value, ValidationContext validationContext)  
  10.     {  
  11.         if (value != null)  
  12.         {  
  13.             for (int i = 0; i < _chars.Length; i++)  
  14.             {  
  15.                 var valueAsString = value.ToString();  
  16.                 if (valueAsString.Contains(_chars[i]))  
  17.                 {  
  18.                     var errorMessage = FormatErrorMessage(validationContext.DisplayName);  
  19.                     return new ValidationResult(errorMessage);  
  20.                 }  
  21.             }  
  22.         }  
  23.         return ValidationResult.Success;  
  24.     }  
  25. } 

Very simple logic, first ensure that the value passed (entered by the user in the TextBox) is not null; if it is not null then go ahead and check that the value contains any of the _chars. If a match is found then immediately return the base error message.

Step 5

Now, go ahead and use this newly created data annotation [ExcludeChar(pass the set of chars)].

The good part of this implementation is that we can override or even localize the error message.

Use any of the following data annotation attributes throughout your application.

// simple annotation attribute


// overriding the error message of data annotation attribute

[ExcludeChar("/.,!@#$%", ErrorMessage="Name contains invalid character.")]

// overriding the error message by localized message

[ExcludeChar("/.,!@#$%", ErrorMessageResourceType=(typeof(MvcApplication1.Views.Demo.ABC)), ErrorMessageResourceName="YourResourceName")]

You will see how easy it is to create and use. Now, open VS and create one yourself and let me know your experience.

Hope this helps.