Custom Data Annotations or Custom Validation Attributes in MVC

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

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

I have recorded a video on this title, you can watch it.



To do this we have following alternatives:


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 (data entered by user in textbox) parameter passed to validate. With validating data in controller action, we can’t reuse it throughout application and much more.

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

Here is the image of what we are going to create.


In the above image, you can see I have used [ExcludeChar(“/.,!@#$%”)], which is nothing but a custom data validation attribute used with Name property. You can also see, when one entering any character defined with the parameter of ExcludeChar in textbox, it displays 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 ExcludeChar class as well.

public class ExcludeChar : ValidationAttribute
{
    ....
}

Step 2

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

public class ExcludeChar : ValidationAttribute
{
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        ....
        return ValidationResult.Success;
    }
}

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

Step 3

So far we have the value typed by the user in 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 string which is the set of characters (/.,!@#$%), this string will be initialized to a local private variable _chars. Also, constructor will assign the default error message to the base class.

public class ExcludeChar : ValidationAttribute
{
    private readonly string _chars;

    public ExcludeChar(string chars)
        : base("{0} contains invalid character.")
    {
        _chars = chars;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        ....
        return ValidationResult.Success;
    }
}

Step 4

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

public class ExcludeChar : ValidationAttribute
{
    private readonly string _chars;

    public ExcludeChar(string chars)
        : base("{0} contains invalid character.")
    {
        _chars = chars;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            for (int i = 0; i < _chars.Length; i++)
            {
                var valueAsString = value.ToString();
                if (valueAsString.Contains(_chars[i]))
                {
                    var errorMessage = FormatErrorMessage(validationContext.DisplayName);
                    return new ValidationResult(errorMessage);
                }
            }
        }
        return ValidationResult.Success;
    }
}

Very simple logic, first making sure passed value (typed by the user in textbox) is not null if so go ahead and check is value contains any of the _chars. If success to find any match, immediately returns the base error message.

Step 5

Now, go ahead the 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 attribute throughout your application.

// simple annotation attribute
[ExcludeChar("/.,!@#$%")]

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

Comments

  1. i try to run this code in VS 13 and MVC 5 and try to debugging with a breakpoint but not call the method "IsValid", something changed in this version? can you help me? greetings

    ReplyDelete
  2. Hi, Can you please confirm the s/w versions, where this code works?
    MVC version
    jquery scripts to be included with thier versions
    Visual studio version

    Thanks in advance.

    ReplyDelete
  3. Hi,

    Can you please confirm the s/w and their versions, where this code works.
    MVC
    jquery includes
    Visual studio version
    and any other

    Thanks in advance,

    ReplyDelete
  4. I have tried with vs 2012 and mvc 4. It is working fine
    Thanks lot for this great expalnation

    ReplyDelete
  5. Easy to understand and I can create custom annotations within 10 minutes. Thank you.

    ReplyDelete
  6. Simple and perferct illustration.
    Thanks.

    ReplyDelete
  7. This does not work. One .Contains() must be a string so you have to say _chars[i].ToString() and even after taking everything you had in a fresh MVC 4 project it does not work - it completely ignores everything.

    ReplyDelete
  8. It is not displaying error message on client side :(

    ReplyDelete
  9. Thank you for such a wonderful Article. Sir, if you write an article on how to give validation group in MVC ..then i rfeally appreciated.Thanks in Advance.

    ReplyDelete

Post a Comment

Popular posts from this blog