Data Annotations And Validation In MVC

Introduction

Validating user input has always been a challenging task for the Web developers. We not only want validation of logic executing in the browser, but we also must validate the logic running on the Server. The client side logic gives the users instant feedback on the information they entered into a Web page and is an expected feature in today’s applications. Meanwhile, the server validation logic is in place because you should never trust information arriving from the network.

Validation
                                 Image source Google

When you look at the bigger picture, you will realize how logic is only one piece of the validation story. You also need to manage the user-friendly and localized error messages associated with the validation logic. We should always place an error message in our UI and provide some mechanism for the user to recover gracefully from the validation failures.

When we talk about the validation in MVC framework context, we primarily focus on validating the model value. Has the user provided a required value? Is the value in range etc.?

In this article, we will see how data annotations work in MVC framework. We will see how annotations go beyond just validation. For keeping this article simple and easily understandable, I am dividing data annotation validation in two parts.

In this article, we will discuss all the predefined data annotation validation listed in System.ComponentModel.DataAnnotations namespace.

Prerequisite

For easy understanding of this article, you should have minimal ASP.Net MVC knowledge. At least, you should be aware about controller view models etc. in MVC and how to create a basic application using ASP.Net MVC.

Overview

For this article, we create an Application i.e ASP.NET MVC Application and named it as DataAnnotationsValidations (you can download the source code for better understanding) and we are using Student Model Class that contains student relation information in which we are going to validate using Data Annotation.

  1. public class StudentModel  
  2. {  
  3.     public Guid StudentId   
  4.   {  
  5.         get;  
  6.         set;  
  7.     }  
  8.     public string FirstName   
  9.     {  
  10.         get;  
  11.         set;  
  12.     }  
  13.     public string LastName   
  14.     {  
  15.         get;  
  16.         set;  
  17.     }  
  18.     public DateTime DateOfBirth  
  19.     {  
  20.         get;  
  21.         set;  
  22.     }  
  23.     public string Address   
  24.     {  
  25.         get;  
  26.         set;  
  27.     }  
  28.     public string ContactNo   
  29.     {  
  30.         get;  
  31.         set;  
  32.     }  
  33.     public string EmailId  
  34.     {  
  35.         get;  
  36.         set;  
  37.     }  
  38.     public string ConfirmEmail   
  39.     {  
  40.         get;  
  41.         set;  
  42.     }  
  43.     public string UserName   
  44.     {  
  45.         get;  
  46.         set;  
  47.     }  
  48.     public string Password   
  49.     {  
  50.         get;  
  51.         set;  
  52.     }  
  53. }  
We have added a student Controller and added Post action method to add a new student. In this Post Action method, we will apply and test the data annotation validation.

Student Controller
  1. using System.Web.Mvc;  
  2. using DataAnnotationsValidations.Models;  
  3.   
  4. namespace DataAnnotationsValidations.Controllers   
  5. {  
  6.     public class StudentController: Controller  
  7.     {  
  8.         // GET: Student  
  9.         public ActionResult Index()   
  10.         {  
  11.             return View();  
  12.         }  
  13.   
  14.         // GET: Student/Create  
  15.         public ActionResult Create()   
  16.         {  
  17.             return View();  
  18.         }  
  19.   
  20.         // POST: Student/Create  
  21.         [HttpPost]  
  22.         public ActionResult Create(StudentModel student)   
  23.         {  
  24.             try  
  25.             {  
  26.                 if (ModelState.IsValid)  
  27.                 {  
  28.   
  29.                     return RedirectToAction("Index");  
  30.                 }  
  31.                 return View();  
  32.             } catch   
  33.             {  
  34.                 return View();  
  35.             }  
  36.         }  
  37.   
  38.     }  
  39. }  
We have added a student view to create Action Method, when we run that view  it will look like the one, shown below:

output

Create Student View
  1. @model DataAnnotationsValidations.Models.StudentModel  
  2.   
  3. @{  
  4.     ViewBag.Title = "Add Student";  
  5. }  
  6.   
  7. <h3>Add New Student</h3>  
  8.   
  9. @using (Html.BeginForm())   
  10. {  
  11.     @Html.AntiForgeryToken()  
  12.       
  13.     <div class="form-horizontal">  
  14.         <hr />  
  15.         @Html.ValidationSummary(true, "", new { @class = "text-danger" })  
  16.         <div class="form-group">  
  17.             @Html.LabelFor(model => model.StudentId, htmlAttributes: new { @class = "control-label col-md-2" })  
  18.             <div class="col-md-10">  
  19.                 @Html.EditorFor(model => model.StudentId, new { htmlAttributes = new { @class = "form-control" } })  
  20.                 @Html.ValidationMessageFor(model => model.StudentId, "", new { @class = "text-danger" })  
  21.             </div>  
  22.         </div>  
  23.   
  24.         <div class="form-group">  
  25.             @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })  
  26.             <div class="col-md-10">  
  27.                 @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })  
  28.                 @Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })  
  29.             </div>  
  30.         </div>  
  31.   
  32.         <div class="form-group">  
  33.             @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })  
  34.             <div class="col-md-10">  
  35.                 @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })  
  36.                 @Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })  
  37.             </div>  
  38.         </div>  
  39.   
  40.         <div class="form-group">  
  41.             @Html.LabelFor(model => model.DateOfBirth, htmlAttributes: new { @class = "control-label col-md-2" })  
  42.             <div class="col-md-10">  
  43.                 @Html.EditorFor(model => model.DateOfBirth, new { htmlAttributes = new { @class = "form-control" } })  
  44.                 @Html.ValidationMessageFor(model => model.DateOfBirth, "", new { @class = "text-danger" })  
  45.             </div>  
  46.         </div>  
  47.   
  48.         <div class="form-group">  
  49.             @Html.LabelFor(model => model.Address, htmlAttributes: new { @class = "control-label col-md-2" })  
  50.             <div class="col-md-10">  
  51.                 @Html.EditorFor(model => model.Address, new { htmlAttributes = new { @class = "form-control" } })  
  52.                 @Html.ValidationMessageFor(model => model.Address, "", new { @class = "text-danger" })  
  53.             </div>  
  54.         </div>  
  55.   
  56.         <div class="form-group">  
  57.             @Html.LabelFor(model => model.ContactNo, htmlAttributes: new { @class = "control-label col-md-2" })  
  58.             <div class="col-md-10">  
  59.                 @Html.EditorFor(model => model.ContactNo, new { htmlAttributes = new { @class = "form-control" } })  
  60.                 @Html.ValidationMessageFor(model => model.ContactNo, "", new { @class = "text-danger" })  
  61.             </div>  
  62.         </div>  
  63.   
  64.         <div class="form-group">  
  65.             @Html.LabelFor(model => model.EmailId, htmlAttributes: new { @class = "control-label col-md-2" })  
  66.             <div class="col-md-10">  
  67.                 @Html.EditorFor(model => model.EmailId, new { htmlAttributes = new { @class = "form-control" } })  
  68.                 @Html.ValidationMessageFor(model => model.EmailId, "", new { @class = "text-danger" })  
  69.             </div>  
  70.         </div>  
  71.   
  72.         <div class="form-group">  
  73.             @Html.LabelFor(model => model.ConfirmEmail, htmlAttributes: new { @class = "control-label col-md-2" })  
  74.             <div class="col-md-10">  
  75.                 @Html.EditorFor(model => model.ConfirmEmail, new { htmlAttributes = new { @class = "form-control" } })  
  76.                 @Html.ValidationMessageFor(model => model.ConfirmEmail, "", new { @class = "text-danger" })  
  77.             </div>  
  78.         </div>  
  79.   
  80.         <div class="form-group">  
  81.             @Html.LabelFor(model => model.UserName, htmlAttributes: new { @class = "control-label col-md-2" })  
  82.             <div class="col-md-10">  
  83.                 @Html.EditorFor(model => model.UserName, new { htmlAttributes = new { @class = "form-control" } })  
  84.                 @Html.ValidationMessageFor(model => model.UserName, "", new { @class = "text-danger" })  
  85.             </div>  
  86.         </div>  
  87.   
  88.         <div class="form-group">  
  89.             @Html.LabelFor(model => model.Password, htmlAttributes: new { @class = "control-label col-md-2" })  
  90.             <div class="col-md-10">  
  91.                 @Html.EditorFor(model => model.Password, new { htmlAttributes = new { @class = "form-control" } })  
  92.                 @Html.ValidationMessageFor(model => model.Password, "", new { @class = "text-danger" })  
  93.             </div>  
  94.         </div>  
  95.   
  96.         <div class="form-group">  
  97.             <div class="col-md-offset-2 col-md-10">  
  98.                 <input type="submit" value="Create" class="btn btn-danger" />  
  99.             </div>  
  100.         </div>  
  101.     </div>  
  102. }  
This is the initial set up and we need to run this data annotation validation project.

Now, we are going to discuss the validation available in data annotation only by one.

Note

Data annotations are the attributes that we can find in the System.ComponentModel.DataAnnotations namespace. These attributes provide Server side validation and the framework also supports client side validation.

Required

We will force the student to give their first name and last name, we can decorate the FirstName and LastName properties of the student Model with required attributes.
  1. [Required]  
  2. public string FirstName   
  3. {  
  4.     get;  
  5.     set;  
  6. }  
  7. [Required]  
  8. public string LastName   
  9. {  
  10.     get;  
  11.     set;  
  12. }  
When we run the page without giving the FirstName and LastName, we will get error message, as shown below:

error

These attributes raise a validation error, if either property value is null or empty. Like all the built in validation attributes the required attributes deliver both client side and server side validation.

With these attributes in place, if someone tries to submit the page without proving the FirstName and LastName, they will see the default error, shown above.

Attributes based on validation ensures that our client and server side validation rules are kept in synchronization because they have been declared in one place.

StringLength

We are forcing the user to enter his name but what happens if he enters a name with enormous length? For student LastName, we will set maximum 60 characters that can be entered. Hence, for doing that, we must decorate LastName with StringLength attributes.
  1. [Required]  
  2. [StringLength(60)]  
  3. public string LastName  
  4. {  
  5.     get;  
  6.     set;  
  7. }  
When we run the page after entering LastName more than 60 characters, we will get the error message, as shown below:

StringLength

We notice that we can attack multiple validation attributes on the single properties. MinimumLength is an optional named parameter we can use to specify the minimum length for a string.
  1. [Required]  
  2. [StringLength(60, MinimumLength = 4)]  
  3. public string LastName   
  4. {  
  5.     get;  
  6.     set;  
  7. }  
Here, last name requires a minimum of four character words.

RegularExpression

Regular expressions are an efficient means to enforce the shape and contains a string value. Suppose, we need to validate the Email ID of the student without sending the Email and Regular expression attributes will do it for us in the way, shown below: 
  1. [RegularExpression(@ "\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z")]  
  2. public string EmailId  
  3. {  
  4.     get;  
  5.     set;  
  6. }  
When a user tries to enter an invalid Email ID and submit the page, he will get validation error, as shown below:

RegularExpression

We will see how to display user friendly error message in a later part of this article.

Range

The Range attributes specifies the minimum and maximum constrains for a numerical number, as shown below:
  1. [Range(18, 30)]  
  2. public int Age  
  3. {  
  4.     get;  
  5.     set;  
  6. }  
In this example, the age for student will be between 10 to 30 years to pass the validation. Here, the first parameter of the attribute is the minimum value and second part is the maximum value. The Range attributes will work with an integer, double and another overloaded versions will take Type as parameters, as shown below:
  1. [Range(typeof(double),"00.00","100.49")]  
Compare

Compare to ensure two properties of a model has same value. For example, Email ID and confirm email ID.
  1. [RegularExpression(@ "\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z")]  
  2. public string EmailId  
  3. {  
  4.     get;  
  5.     set;  
  6. }  
  7. [Compare("EmailId")]  
  8. public string ConfirmEmail  
  9. {  
  10.     get;  
  11.     set;  
  12. }  
If both Email ID and confirm Email ID are not same, the user will get model validation error, as shown below:

Compare

Display

Display attribute sets the friendly name for the model properties. We can use the Display attributes to fix the name for label for LastName field.
  1. [Required]  
  2. [StringLength(60, MinimumLength = 4)]  
  3. [Display(Name = "Last Name")]  
  4. public string LastName  
  5. {  
  6.     get;  
  7.     set;  
  8. }  
When we will set the last name display properties then it will look like

Display

ScaffoldColumn

The ScaffoldColumn attribute hides the properties from HTML helper such as EditorForModel and DisplayForModel,
  1. [ScaffoldColumn(false)]  
  2. public string Address   
  3. {  
  4.     get;  
  5.     set;  
  6. }  
Address will not be shown in UI if ScaffoldColumn is false.

DisplayFormat

DisplayFormat attribute handles formatting option for the properties via named parameters. We can provide an alternative text for display, when property is null. We can also specify data format string, currency symbol etc. Suppose we have student income property for which we want to set currency symbol, which is shown below:
  1. [DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:c}")]  
  2. public Decimal Income   
  3. {  
  4.     get;  
  5.     set;  
  6. }  
By default, ApplyFormatInEditMode is false because MVC binder might not to parse the value formatted for display only.

ReadOnly

If we decorate an attribute with ReadyOnly attribute, the user can not set that property's value.
  1. [ReadOnly(true)]  
  2. public Decimal Income  
  3. {  
  4.     get;  
  5.     set;  
  6. }  
DataType

DataType attributes enable us to provide the runtime information about the specific purpose of the properties. For example, a property of type string can have various scenarios as it might hold Email address, URL or a password. There are various data types that includes Currency, Date, Time, Password and MultilineText etc.
  1. [DataType(DataType.Password)]  
  2. public string Password   
  3. {  
  4.     get;  
  5.     set;  
  6. }  
When we set DataType as password, we will see the password field in non readable format.

DataType

Custom Error Message and Localization

Every validation attribute allows you to pass the name parameter with custom error message. We can configure the default error message with a user friendly error message as we need to pass the custom error message with ErrorMessage named attribute shown below:
  1. [RegularExpression(@ "\A(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)\Z", ErrorMessage = "Invalid Email Id")]  
  2. public string EmailId  
  3. {  
  4.     get;  
  5.     set;  
  6. }  
If a user will not input the correct Email format, he will get an error, shown below: 

Custom Error Message

The ErrorMessage can also have a single format item in the string. The built in attributes format provide the properties name with a user friendly message.
  1. [Required(ErrorMessage="Your {0} is required")]  
  2. [StringLength(60,MinimumLength =4,ErrorMessage ="{0} should be between 4 to 60 Char")]  
  3. public string LastName { getset; }  
Custom Error Message

If we create an Application with globalization and localization features then this string message will be not sufficient. Hence, in this case, we can configure the error message with the resource string.
  1. [Required(ErrorMessageResourceType = typeof(ErrorMessage), ErrorMessageResourceName = "LastName")]  
  2. public string LastName { getset; }  
In this case, ErrorMessage considers a resource file name with LastName as a key for an associated error message.

Validation and Model Binding

By default, ASP.Net MVC framework executes validation logic during model binding. In Controller side, we need to check
  1. if (ModelState.IsValid)  
  2. {  
  3. }  
We can also use,
  1. if(TryUpdateModel(newStudent)){}  
We can also check Individual validation, as shown below: 
  1. if (ModelState.IsValidField("LastName") == false)  
  2. if (ModelState["LastName"].Errors.Count > 0)  
To display the error message in our view, we must need to include following line with all the properties in which we are applying validation.
  1. @Html.ValidationMessageFor(model => model.Password)  
Conclusion

In this article, we learned about the built in data annotation validation in ASP.Net MVC framework. If you have any question or comments regarding this article, please post it in the comment section of this article. In the next article, we will learn to create a custom validation in ASP.NET MVC. Thank you for reading this article. I hope you like it.