Validation Attributes in Code-First






4.83/5 (4 votes)
Validation attributes in code-first
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:
- Validation attributes
- 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 than 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 information 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, is 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 valueDateTime
– date and time valueDuration
EmailAddress
Html
– specify that HTML code is expectedImageUrl
– URL to an imageMultilineText
– usestextarea
instead oftext
as input type in forms.Password
PhoneNumber
PostalCode
Text
Time
Upload
– a file upload data typeUrl
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:
- Code First DataAnnotations – post by Julie Lerman written from the hills of Vermont
- Validation attribute class – specifying all properties and methods
- C# Regular Expressions Cheat Sheet – by Mike Brind
- Entity Framework Code First DbContext – Validation – by Muhammad Shujaat Siddiqi