Click here to Skip to main content
Click here to Skip to main content

Tagged as

Go to top

Validation attributes in Code-First

, 8 Mar 2014
Rate this:
Please Sign up or sign in to vote.
DataAnnotations are really helpful when creating a model in Entity Framework Code-First. They are a simple way of instructing EF how you want the model to be structured and how it should translate the model into a relational database. You can also use validation rules to specify what values are allo

DataAnnotations are really helpful when creating a model in Entity Framework Code-First. They are a simple way of instructing EF how you want the model to be structured and how it should translate the model into a relational database. You can also use validation rules to specify what values are allowed in your parameters. When using MVC and scaffolding these validation rules are also used when creating the user interface for you. You get a lot for free by simply adding the right DataAnnotations to your model. It’s really something worth looking into if you haven’t done it so far.

The attributes used in Code-First can be classified into two categories:

  1. Validation attributes
  2. Database schema related attributes

In this post I’ll look into the first category and will also provide with code examples for each of the attributes. If you think I’ve missed out on any good ones you’re more then welcome to write a comment. Later on I’ll post a text based upon the second category of attributes as well.

How to use attributes

All attributes are written just before the property/class/function they’re validating, with zero or more mandatory parameters followed by a list of optional named parameters. The attribute StringLength, for example, has one mandatory parameter: MaximumLength

[StringLength(10)]
public string MembershipCode { get; set; }

…but can also attach named parameters like MinimumLength and ErrorMessage. When using Visual Studio you’re provided with a list of all available named parameters.

[StringLength(20, MinimumLength = 5, ErrorMessage = "Use 5-20 characters")]
public string UserName { get; set; }

Other attributes like Required can be without parameters just fine.

[Required]
public string CountryCode { get; set; }

How MVC uses validation attributes to validate incoming variables

In the controller’s scaffolded methods marked with HttpPost you can see the ModelState object being used. The ModelState object contains info about all the incoming parameters and whether they validate according to the specified model’s validation attributes. In the example below incoming variables are matched towards the Customer object. If the Customer object specifies that CountryCode is Required but no CountryCode is listed among the incoming variables, the ModelState would signal a validation failure and the user would be redirected back to the page with an error message. This validation is done automatically for you and shows one example of how useful the attributes can be.

[HttpPost]
public ActionResult Edit(Customer customer)
{
    if (ModelState.IsValid) {
        // Save customer
        return RedirectToAction("Index");
    } else {
        return View();
    } 
}

Validation attributes

Here follows a list of the most common validation attributes available when building a model in code-first.

Compare

Compare value of a property to another property. The Compare attribute exists in both System.Web.Mvc and System.Component.DataAnnotations so you need to specify namespace for attribute if both namespaces are included in the using section. The example below makes sure that the properties Email and EmailVerify are the same.

public class RegisterEmailAddressViewModel
{
    [Required]
    public int UserId { get; set; }

    [DataType(DataType.EmailAddress)]
    public string Email { get; set; }

    [System.ComponentModel.DataAnnotations.Compare("Email", 
        ErrorMessage = "Verify email is invalid")]
    public string EmailVerify { get; set; }
}

Please note that the example above is a view model and is not intended for database storage. If you use the Compare attribute in a database model class you probably also want to attach a [NotMapped] attribute as well since you don’t want to store the email address twice in the database.

CustomValidation

Allows you to write your own validation attribute. Simply create a class implementing the ValidationAttribute class. Add a public static function that accepts a value to be compared and return an instance of ValidationResult.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class OldEnoughValidationAttribute : ValidationAttribute
{
    public static ValidationResult IsOldEnough(int givenAge)
    {
        if (givenAge >= 20)
            return ValidationResult.Success;
        else
            return new ValidationResult("You're not old enough");
    }
}

You can then use the newly created attribute in the following way by specifying the attribute and the static function performing the validation:

public class Customer 
{
    [CustomValidation(typeof(OldEnoughValidationAttribute), "IsOldEnough")]
    public int Age { get; set; 
}

Another way of creating and using custom validation is, instead of creating the public static class above, to override the existing IsValid function in the ValidationAttribute class.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
public class OldEnoughValidationAttribute : ValidationAttribute
{
    public int LimitAge { get; set; }
    public OldEnoughValidationAttribute(int limitAge)
    {
        LimitAge = limitAge;
    }
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        int val = (int)value;

        if (val >= LimitAge)
            return ValidationResult.Success;
        else
            return new ValidationResult(ErrorMessageString);
    }
}

You can then just mark your properties with this new attribute and the validation will be done automatically.

public class Customer 
{
    [OldEnoughValidation(20, ErrorMessage = "You're not old enough")]
    public int Age { get; set; 
}

DataType

Allows you to specify a datatype that is more specific than the database intrinsic types. This can be used to provide more accurate validation and appropriate display for user. Valid datatypes are:

  • CreditCard
  • Currency
  • Custom
  • Date – date value
  • DateTime – date and time value
  • Duration
  • EmailAddress
  • Html – specify that Html code is expected
  • ImageUrl – url to an image
  • MultilineText – uses textarea instead of text as input type in forms.
  • Password
  • PhoneNumber
  • PostalCode
  • Text
  • Time
  • Upload – a file upload data type
  • Url

Use the attribute in the following way:

public class Customer
{
    [DataType(DataType.EmailAddress, ErrorMessage = "Not a valid email address")]
    public string Email { get; set; }
}

Display

Helps you specify a text that can be used as label for the property’s value when editing in forms.

public class Customer
{
    [Display(Name = "Email is confirmed")]
    public bool EmailIsConfirmed { get; set; }
}

MaxLength

Maximum length of array or string

public class Customer
{
    [MaxLength(20, ErrorMessage = "Name can't be longer than 20 characters")]
    public string Name { get; set; }
}

MinLength

Minimum length of array or string

public class Customer
{
    [MinLength(5, ErrorMessage = "Name can't be shorter than 5 characters")]
    public string Name { get; set; }
}

Range

Specify a numeric minimum and maximum range for a property.

public class Customer
{
    [Range(0, 120, ErrorMessage = "Age has to be between 0 and 120")]
    public int Age { get; set; }
}

RegularExpression

Validates property against regular expression.

public class Customer
{
    [RegularExpression(@"^[A-Z]{2}$", 
        ErrorMessage = "Country code can only be two alphabetic characters in CAPITALS")]
    public string CountryCode { get; set; }
}

Required

Property must contain a value and can’t be left empty.

public class Customer
{
    [Required(
        AllowEmptyStrings=false, 
        ErrorMessage="User name can't be empty")]
    public string UserName { get; set; }

    [Required]
    public string City { get; set; }
}

StringLength

Specifies maximum length of a string with option to specify minimum length and error message.

public class Customer
{
    [StringLength(20, 
        MinimumLength = 5, 
        ErrorMessage = "UserName has to be between 5 and 20 characters")]
    public string UserName { get; set; }
}

MembershipPassword (System.Web.Security)
Validates property as password with given requirements.

public class Customer
{
    [Required]
    public string UserName { get; set; }

    [MembershipPassword(
        MinRequiredPasswordLength=8, 
        ErrorMessage="Your password needs to be at least 8 characters long", 
        MinRequiredNonAlphanumericCharacters=1, 
        MinNonAlphanumericCharactersError="At least one of the characters needs to be non-alphanumeric")]
    public string Password { get; set; }
}

More resources

If you want to read more about DataAnnotations I suggest the following links:

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Johan Ohlin
CEO BJ Focus Ltd
United Kingdom United Kingdom
Johan is the CEO of BJ Focus Ltd, a UK company specialised in the development of business structure platforms helping companies to structure flows of organisable data.
 
He writes articles on the BJ Lab's blog, especially when his customers keep asking the same thing. You might find a few of these articles here on CodeProject.
 
Currently his focus is on building MVC web apps on the Azure platform, but PHP and MySQL get their share of attention as well.
 
Johan has double masters, in business and in software development, and an MCTS in .Net Framework 4, web applications.
Follow on   Twitter   Google+   LinkedIn

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web04 | 2.8.140926.1 | Last Updated 9 Mar 2014
Article Copyright 2014 by Johan Ohlin
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid