Posted on 3/29/2020 5:01:27 PM by Admin

DataAnnotaion in Asp.Net MVC

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 specifies that the value is mandatory and cannot be skipped. [Required(ErrorMessage="Please enter firstName"),MaxLength(35)]
DataType specifies the datatype of the model property. [DataType(DataType.CreditCard)]
Range Using this attribute we can set a range between two numbers. [Range(18,45,ErrorMessage="Please enter between 18 and 45")]
StringLength specifies maximum and minimum length of the property. [StringLength(35,ErrorMessage="Do not enter more than 35 characters")]
DisplayName Using this attribute we can specify property name to be displayed on view. [Display(Name="Employee Name")]
MaxLength specifies maximum length of property. [MaxLength(25)]
DisplayFormat This attribute allows us to set date in the format specified as per the attribute. [DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}")]
RegularExpression specifies regex pattern for the property like Email ID,specific URL etc [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 Parameters Return
@Html.ValidationMessage("Name")

Displays a validation message if an error exists for the specified field in the System.Web.Mvc.ModelStateDictionary object.

modelName: The name of the property or model object that is being validated.
htmlAttributes: An object that contains the HTML attributes for the element.

If the property or object is valid, an empty string; otherwise, a span element that contains an error message.

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

Returns the HTML markup for a validation-error message for each data field that is represented by the specified expression, using the specified message.

expression: An expression that identifies the object that contains the properties to render.
validationMessage: The message to display if the specified field contains an error.

If the property or object is valid, an empty string; otherwise, a span element that contains an error message.

@Html.ValidationSummary()

Returns an unordered list (ul element) of validation messages that are in the System.Web.Mvc.ModelStateDictionary object.

Parameters: message: The message to display if the specified field contains an error.
htmlAttributes: A dictionary that contains the HTML attributes for the element.
A string that contains an unordered list (ul element) of validation messages.

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 accept model property name as 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 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 parameter one is incoming submitted value and other is ValidationContext.ValidationContext gives us the access of containing container meaning it gives us the access of the class which is using it.
3.ValidationContext.ObjectInstance is used to create an object of container class.In our case ,we are about to use this attribute over Employee model class ,so i have type casted it into Employee Type.
4.I have not used any Database logic,you are free to write any logic you want.
5.If error occurs simply return an instance of ValidationResult with error message as parameter or return Success,which is a readonly static field.
6.Mark the Name property of 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