CodeDigest.Com Logo
Featured:

Input Validations in Asp.Net MVC - Clientside and Serverside using DataAnnotation Model Validation

Tagged as: Asp.Net MVC Posted By

Input validations are one of the primary task we do in any of the application we develop. In Asp.Net MVC framework, we have a support for inbuilt validation framework that takes care of both client side and server side validations with very less effort. The Asp.Net MVC Model binding framework uses the data annotations attributes configured in the model to perform validations when the form is posted back to the server. Asp.Net MVC also performs an automatic client validations when the following appsettings values are set to true in Web.Config file.

 

<add key="ClientValidationEnabled" value="true" />

<add key="UnobtrusiveJavaScriptEnabled" value="true" />

 

Please note the client side validations requires jQuery and Microsoft.jQuery.Unobtrusive.Validation Nuget package in the project. The script that is responsible for client side validations is jquery.validate.unobtrusive.min.js and and jquery.validate.js file.

Let’s build a simple Asp.Net MVC project by using a simple Employee-Department model to demonstrate input validations using DataAnnotations attribute. We will use EntityFramework Code First for data access. You can download the source attached at the end of this article for reference.

The System.ComponentModel.DataAnnotations namespace has number of validation attributes for defining the validation rules for the model. They are,

  1. Required – Makes the field mandatory.

  2. StringLength or MaxLength – Sets maximum length to the input field.

  3. RegularExpression – Validates the input and allows only if the input value matches the regular expression

  4. Compare – Compares the field value with another field value and allows only if it matches. Example: Password and ConfirmPassword

  5. Range – Checks and allows only if the input is in the numeric range specified.

We can also do custom validations by creating our own validation attributes. Next section, let’s see how to use the above validation attributes to configure input validation in Asp.Net MVC. Assuming, you have created an Asp.Net MVC 5.0 project with all Nuget packages required for MVC and Entity Framework lets go ahead and build our model.

Defining Model with Validation Attribute

public class Employee
{
    //Table properties
    [Key]
    public int EmployeeId { get; set; }

    [Required]
    [Display(Name ="Department")]
    public int DepartmentId { get; set; }

    [MaxLength(50)]
    [Required]

    [Display(Name = "First Name")]
    public string FirstName { get; set; }

    [MaxLength(50)]
    [Required]

    [Display(Name = "Last Name")]
    public string LastName { get; set; }

    [MaxLength(50)]
    [Required]

    [Display(Name = "Address Line1")]
    public string Address1 { get; set; }

    [MaxLength(50)]
    [Display(Name = "Address Line2")]
    public string Address2 { get; set; }

    [MaxLength(50)]
    [Required]

    [Display(Name = "City")]
    public string City { get; set; }

    [MaxLength(50)]
    [Required]

    [Display(Name = "State")]
    public string State { get; set; }

    [MaxLength(50)]
    [Required]

    [Display(Name = "Country")]
    public string Country { get; set; }

    [MaxLength(10)]
    [Required]

    [Display(Name = "Postal Code")]
    public string PostalCode { get; set; }

    [MaxLength(100)]
    [RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}",ErrorMessage ="Check email address format!")]
    [Required]

    [Display(Name = "Email")]
    public string Email { get; set; }

    [MaxLength(100)]
    [RegularExpression(@"[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}", ErrorMessage = "Check email address format!")]
    [Compare("Email")]
    [Required]

    [Display(Name = "Retype Email")]
    public string ConfirmEmail { get; set; }

    [Display(Name = "Date of Birth")]
    public DateTime? DOB { get; set; }

    [MaxLength(10)]
    [Required]

    [Display(Name = "Gender")]
    public string Gender { get; set; }

    [Display(Name = "Are you a permanent employee?")]
    public bool IsPermanent { get; set; }

    [Range(0.00,10000.00)]
    [Display(Name = "Salary")]
    public decimal Salary { get; set; }

    public virtual Department Department { get; set; }
}
 

The above Employee model has used all the validation attributes for configuring the validations. Each validation attributes emit a default validation error message if we have not configured. The attributes also allows error message to be set by us. I have set the custom error message in the RegularExpression validation attribute for Email field.

Now, in EmployeeController, let’s build an edit page for the Employee model. The below edit() get action will present a edit screen for editing the employee details.

Edit Action:

public ActionResult edit(int id)
{
    Employee emp = db.Employees.Where(e => e.EmployeeId == id).FirstOrDefault();
    ViewBag.DepartmentListItems = db.Departments.Distinct().Select(i => new SelectListItem() { Text = i.DepartmentName, Value = i.DepartmentId.ToString() }).ToList();
    return View(emp);
}
 

Let’s include a strongly typed view for Employee model for the above edit action and use the default scaffolded view.

@model EmployeeMaintenance.Models.Employee
@{
    ViewBag.Title = "edit";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Edit Employee</h2>

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>Employee</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.EmployeeId)

        <div class="form-group">
            @Html.LabelFor(model => model.DepartmentId, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model => model.DepartmentId, ViewBag.DepartmentListItems as IEnumerable<SelectListItem>, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.DepartmentId, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.FirstName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.FirstName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.FirstName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.LastName, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.LastName, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.LastName, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Address1, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Address1, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Address1, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Address2, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Address2, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Address2, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.City, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.City, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.City, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.State, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.State, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.State, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Country, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Country, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Country, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.PostalCode, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.PostalCode, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.PostalCode, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Email, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Email, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Email, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.DOB, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.DOB, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.DOB, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Gender, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Gender, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Gender, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.IsPermanent, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                <div class="checkbox">
                    @Html.EditorFor(model => model.IsPermanent)
                    @Html.ValidationMessageFor(model => model.IsPermanent, "", new { @class = "text-danger" })
                </div>
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.Salary, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Salary, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Salary, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}
 

The POST action for the above edit view is below.

[HttpPost]
public ActionResult edit(Employee empModel)
{
    if (ModelState.IsValid)
    {
        Employee emp = db.Employees.Where(e => e.EmployeeId == empModel.EmployeeId).FirstOrDefault();
        if (emp != null)
        {
            emp.FirstName = empModel.FirstName;
            emp.LastName = empModel.LastName;
            emp.Address1 = empModel.Address1;
            emp.Address2 = empModel.Address1;
            emp.State = empModel.State;
            emp.State = empModel.State;
            emp.Country = empModel.Country;
            emp.PostalCode = empModel.PostalCode;
            emp.DOB = empModel.DOB;
            emp.Email = empModel.Email;
            emp.ConfirmEmail = empModel.ConfirmEmail;
            emp.Salary = empModel.Salary;
            emp.IsPermanent = empModel.IsPermanent;
            db.SaveChanges();
            return Redirect(Url.Action("details", new { id = emp.EmployeeId }));
        }
    }
    ViewBag.DepartmentListItems = db.Departments.Distinct().Select(i => new SelectListItem() { Text = i.DepartmentName, Value = i.DepartmentId.ToString() }).ToList();
    return View(empModel);
}
 

The above post action will allow to save changes only when ModelState.IsValid is true. By default, model validations on the server side will happen during model binding and the IsValid property is set to true if validation passes. The validation error message are noted in the ModelState object and it is used by the @Http.ValidationMessageFor() helper methods to display the error message for each field.

When executed, you can see the validation message appearing for false inputs like below.

The above view uses the default scaffolded view which uses generic @Html.EditorFor() helper methods that renders the input html control based on the field types. We can use other HTML helper methods here. For example, you can use @Html.TextBoxFor and @Html.ValidationMessageFor for displaying textbox and validation message.

 

@Html.TextBoxFor(model => model.FirstName, new { @class = "form-control" } )

@Html.ValidationMessageFor(model => model.FirstName,"",new { @class = "text-danger" })

 

Or we can use @Html.TextBox and @Html.ValidationMessage like below instead of using @Html.EditorFor() helper methods.

 

@Html.TextBox("FirstName", Model.FirstName, new { @class = "form-control" })

@Html.ValidationMessage("FirstName", new { @class = "text-danger" })

 

 

Calling Model Binding Explicitly

As I said in previous section, the model validations will occur during model binding in POST action. We can also call the model binding manually over the posted form collection to populate the model object directly form the Http FormCollection object. The below edit POST action will call model binding explicitly using TryUpdateModel() method which will use the posted form collection values to populate the model object. The method will return true when all the validations passes and the model binder is able to populate all the values to model else it returns false. The validation error messages and IsValid flag are noted in ModelState object appropriately.

[HttpPost]
public ActionResult edit(int EmployeeId, FormCollection collection)
{
    Employee emp = db.Employees.Where(e => e.EmployeeId == EmployeeId).FirstOrDefault();
    if (TryUpdateModel(emp))
    {
        if (ModelState.IsValid)
        {
            if (emp != null)
            {
                db.SaveChanges();
                return Redirect(Url.Action("details", new { id = emp.EmployeeId }));
            }
        }
    }
    ViewBag.DepartmentListItems = db.Departments.Distinct().Select(i => new SelectListItem() { Text = i.DepartmentName, Value = i.DepartmentId.ToString() }).ToList();
    return View(emp);
}
 

Thus, we have seen how to configure the model validation using DataAnnotations attributes which in turned enabled input validations in Asp.Net MVC application. Download the source and see it in action!

 

 



Feedback

Comments