DataAnnotaion in Asp.Net MVC

by Sachin Singh


Posted on Sunday, 29 March 2020

Tags: DataAnnotation in MVC Html.validationMessage Html.ValidationMessageFor Html.ValidationSummary custom validation attribute

In Asp.Net WebForm we had different validation controls like RequiredField validator,Compare validator,Range validator,RegularExpression validator etc to validate user inputs in server controls.

In Asp.Net MVC ,we have DataAnnotations ,which is much easier to use than webform's validators.

DataAnnotations are actually attributes in MVC ,which can be applied to any model property. Each DataAnnotion has different validation rules.

Below are the different DataAnnotations available in Asp.Net MVC.

Attribute Description Syntax
Required use it make a field required. [Required(ErrorMessage="Please enter Name"),MaxLength(50)]
DataType use it to specify the data type of property of an entity explicitly. [DataType(DataType.EmailAddress)]
Range use it to specify a numeric range of values for a field. [Range(20,60,ErrorMessage="Please enter between 20 and 60")]
StringLength use it specify the maximum and minimum length of a string property. [StringLength(50,ErrorMessage="Do not enter more than 50 characters")]
DisplayName use it on a property so that it could be used in view for display purposes. [Display(Name="Employee Name")]
MaxLength use it to specify the maximum accepted length for a property. [MaxLength(150)]
DisplayFormat use this attribute to specify a specific date format. [DisplayFormat(DataFormatString = "{dd/MM/yyyy}")]
RegularExpression use it to explicitly define regex pattern for any field [RegularExpression(@"^\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$", ErrorMessage = "Email is not valid.")]

Before ,using DataAnnotation attribute to show validation message on view, it becomes important to know how validation actually works and what happens when submitted values do not satisfy the validation rules of specified DataAnnotation attribute.I am pointing towards one important property called as ModelState.Let's understand what ModelState actually is.

ModelState:-

ModelState has two purposes:-
  1. To store values submitted to the server.
  2. To store validation error associated with those values.

The name ModelState is actually little misleading ,despite its Name ,it has nothing to do with model class.Actually ,it doesn't know anything about model class ,it only has names,values and errors of submitted values.

ModelState is actually a property of Controller class ,so it can only be accessible to those classes that inherit from System.Web.MVC.Controller.
  • ModelState is of Type ModelStateDictionary which holds the collection of name and value pairs that were submitted to the server during a POST.
  • It contains a collection of error messages for each value submitted.

Now,It's time to implement validation .To display validation messages in the view, based on the validation rules of specified DataAnnotation attribute or attached error message with the attribute.we can use below Html Helpers.

Html Helper Summary
@Html.ValidationMessage("Name")

Displays a validation message if an error exists for the specified field .

@Html.ValidationMessageFor(x=>x.Name)

use it display the validation error message specified in the model property using data-annotation.

@Html.ValidationSummary()

use it show all error messages at a time in an unordered list. .

ValidationMessage

Like other html helpers it is also an extension method of Html Helper class which can be accessed in the view with @Html object,where Html is an object of Html helper class and @ symbol is used to specify server side object in razor view.

It is loosely typed and accepts model property name as a string which is used to show validation message in the view. So, it is your duty to specify the same name to this Html Helper as your property name is.


  public static MvcHtmlString ValidationMessage(this HtmlHelper htmlHelper, string 
  modelName, IDictionary<string, object> htmlAttributes);

As I have already discussed ModelState captures all the values and errors associated with the values which are submitted to the server.Asp.Net MVC framework automatically enforces these validation errors to the Html helpers if ModelState has any related errors.

ValidationMessageFor

It also has the same purpose that is to show the validation messages in the MVC View, it is the strongly-typed version of ValidationMessage Html Helper which can be accessed with @Html syntax in razor view.


   public static MvcHtmlString ValidationMessageFor<tmodel, tproperty>(this 
  HtmlHelper<tmodel>htmlHelper, Expression<func<tmodel, tproperty>> expression, 
  string validationMessage)

ValidationSummary

If you want to show all the validation errors in one go,then this Extension method is the best for you. validation summary generates an unordered list of validation messages that are in the ModelStateDictionary object.


  public static MvcHtmlString ValidationSummary(this HtmlHelper htmlHelper, bool excludePropertyErrors, string message);

Now let's take examples to show both Inbuilt error message and custom errors.

Step 1.Create a model class with some properties and DataAnnotation attributes like below.


    public class Employee
    {
       
       [Required]
        public string Name { get; set; }
        [Required]
        [Range(18,45)]
        public int Age { get; set; }
        [DataType(DataType.EmailAddress)]
        public string Email { get; set; }
        [DataType(DataType.PhoneNumber)]
        public int Phone { get; set; }
       
    }

Step 2. Create two Action Methods one for returning a view and second to capture validation error or to save the value in database.


        public ActionResult SaveEmployee(Employee emp)
        {
            if (ModelState.IsValid)
            {
                //write logic to save into database here
           
            }
            return View("Validation",emp);
            
        }
        public ActionResult Validation()
        {
            return View();
        }

Step 3.Design the view using html helpers like below.


        @{
    ViewBag.Title = "Validation";
       }

<h2>Validation</h2>
@using MVCExample.Models
@model Employee
<style>
    .error{
        color:red;
    }
</style>
<form action="/Student/SaveEmployee" method="post">
    <table>
        <tr>
            <td>@Html.LabelFor(l=>l.Name)</td>
            <td>@Html.TextBoxFor(m=>m.Name) @Html.ValidationMessageFor(m => m.Name, "", new {@class="error" })</td>
        </tr>
        <tr>
            <td>@Html.LabelFor(l => l.Age)</td>
            <td>@Html.TextBoxFor(m => m.Age)@Html.ValidationMessageFor(m => m.Age, "", new { @class = "error" })</td>
        </tr>
        <tr>
            <td>@Html.LabelFor(l => l.Email)</td>
            <td>@Html.TextBoxFor(m => m.Email)@Html.ValidationMessageFor(m => m.Email, "", new { @class = "error" })</td>
        </tr>
        <tr>
            <td>@Html.LabelFor(l => l.Phone)</td>
            <td>@Html.TextBoxFor(m => m.Phone)@Html.ValidationMessageFor(m => m.Phone, "", new { @class = "error" })</td>
        </tr>
        <tr>
            <td colspan="2"><button type="submit">Save</button></td>
           
        </tr>
    </table>
   
</form>

Now run the application and violate some validation knowingly and check whether validations are working or not.

Validation in MVC
validation in MVC

As you can see the inbuilt validation error messages are self sufficient yet if you want custom error messages then you have two options:-

  1. Use overloaded version of DataAnnotation attribute of to specify custom error like below.


         [Required(ErrorMessage="can not be empty")]
        public string Name { get; set; }
        [Required]
        [Range(18,45,ErrorMessage="Age must be between 18 and 45")]
        public int Age { get; set; }

  2. Use overloaded version of Html Helper method to specify custom error.


        @Html.ValidationMessageFor(m => m.Name,"can not be empty", new {@class="error" })

Custom validation Attribute:-

All the available DataAnnotation attributes are good and sufficient for most the business validations , but there may be situation where these attributes fails to serve the purpose and you need to write your own validation logic.

Asp.Net MVC provides us a way to make our own custom validation attribute as per our requirement.In order to make custom validation attribute we have to inherit our class from ValidationAttribute and implement (override) its IsValid method.

Let's understand it with an Example.

Suppose we have to validate whether User Name is in use or available.We will create a custom validation attribute for the same.


   public class UserNameCheck:ValidationAttribute
     {
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            string[] names = {"sachin","arjun","vikash","Govinda","Salman" };
            Employee emp = (Employee)validationContext.ObjectInstance;
            bool istrue = names.Any(x => x == emp.Name);
            if (istrue)
            {
                return new ValidationResult("UserName is in use");
            }
            return ValidationResult.Success;
        }
     }

1.I have used the same Employee model so that it would be easy for you to understand.
2.I have used the second overloaded version of IsValid() which accepts two parameters one is incoming submitted value and the other is ValidationContext.ValidationContext gives us access to containing container meaning it gives us access to the class which is using it.
3.ValidationContext.ObjectInstance is used to create an object of the container class. In our case, we are about to use this attribute over the Employee model class, so I have typecast it into Employee Type.
4.I have not used any Database logic, you are free to write any logic you want.
5.If an error occurs simply return an instance of ValidationResult with an error message as a parameter or return Success, which is a read-only static field.
6.Mark the Name property of the Employee class with this custom attribute like below.


     public class Employee
       {
        [Required(ErrorMessage="can not be empty")]
        [UserNameCheck]
         public string Name { get; set; }
         [Required]
         [Range(18,45,ErrorMessage="Age must be between 18 and 45")]
         public int Age { get; set; }
         [DataType(DataType.EmailAddress)]
         public string Email { get; set; }
         [DataType(DataType.PhoneNumber)]
         public int Phone { get; set; }
      }

We have already created the view in previous example, now its time to run the application and check the validation.

custom validation
custom validation user name is in use