Customized Data Annotations in MVC

Can’t find the right data annotation validation needed for one of your properties? Easily create your own in MVC with a few simple steps:

Let’s say you want to limit email for account registration and login to a specific set of domains. This validation can easily be added via customized data annotations.

The first step is to create a class that inherits the ValidationAttribute class, located in the System.ComponentModel.DataAnnotations namespace as follows:

using System.ComponentModel.DataAnnotations;

public class EmailDomainsAttribute: ValidationAttribute
{ }

Next we create a constructor. Depending on what type of validation we want to provide, we can create a constructor with or without parameters. In our case we do not need parameters, so we will create an empty constructor.

After that we need to override the IsValid method.

using System.ComponentModel.DataAnnotations;

public class EmailDomainsAttribute: ValidationAttribute {

public EmailDomainsAttribute() { }

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{

return ValidationResult.Success;

}

}

Now, we add in the restrictions we want to set on the domains. There are several ways of doing this – either querying a database containing acceptable domains, hardcoding them into our attribute class, or passing them in via Data Annotations in our Models (in which case we need to add a receiving parameter in our constructor to store these).

For sake of simplicity, let’s just use a hardcoded domain.
Don’t use hardcoded data in your projects – this is always bad coding practice

using System.ComponentModel.DataAnnotations;

public class EmailDomainsAttribute: ValidationAttribute {

public EmailDomainsAttribute() { }

protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{

if (value == null) return new ValidationResult(“Do not leave field blank.”);

String domain = value.ToString();

if(domain.Contains(“gmail.com”)) {

return ValidationResult.Success;

} else {

return new ValidationResult(“Invalid domain.”);

}

}

}

Now, in your Model properties, you can use this Data Annotation simply by class name:

[EmailDomainsAttribute]
public String Email { get; set; }

As mentioned above, we can send in parameters via our Models. To achieve this, we could add a string parameter to our EmailDomainsAttribute constructor and save the parameter to a local variable, and compare the value passed to IsValid with this variable – we then send in this variable via the Data Annotation:

[EmailDomainsAttribute(“gmail.com”)]

A third solution, as mentioned, is to query a database containing acceptable domains we want to allow.

And finally, to prevent hardcoded error messages (remember – hardcoding is never good, it reduces code reusability and is error-prone), we can pass in error messages via our Models through the ErrorMessage attribute:

[EmailDomainsAttribute(ErrorMessage=”Invalid domain”)]

and customize the message as desired (hint: passing ‘{0}’ inside the ErrorMessage passes along the property name). To get this message, we need to add one more line of code to our IsValid method:

var errorMessage = FormatErrorMessage(validationContext.DisplayName);

Now we use this variable instead of our hardcoded error strings.

That’s all there is to it. This allows us to create any kind of data annotation validation we need, no matter the complexity.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s