Introduction
The most common web application security weakness is the failure to properly validate input from the client or environment. Data from the client should never be trusted for the client has every possibility to tamper with the data. So it needs to ensure that data is not only validated, but business rule is correct.
This article explains how to implement validation in an ASP.NET MVC application. I am using a simple form to demonstrate the basic validation in MVC4. Here, we will see different approaches to validate data from clientside and from serverside.
Basically, this article contains the following approaches:
- By using Data Annotations
- By using
ModelState
object (Explicit Model Validation)
- By using jQuery Validation plug-in
- By using Fluent Validation package
Using the Code
In MVC Model
are the class which contains domain classes and the validations. Validation plays a core part in a Model.
First of all, let's create an application with sample model, view and controller. After that, we will apply different approaches to validate data.
Model (UserModel.cs)
namespace SampleApplication.Models
{
public class UserModel
{
public string Name { get; set; }
public string Email { get; set; }
public string MobileNo { get; set; }
}
}
View (User.cshtml)
@model SampleApplication.Models.UserModel
@{
ViewBag.Title = "User Details";
}
<br /><br />
@using (Html.BeginForm())
{
<fieldset>
<legend>Form</legend>
<div class="form-group">
@Html.LabelFor(model => model.Name, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Email, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.Email, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.MobileNo, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.MobileNo, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="OK" />
</div>
</div>
</fieldset>
}
Controller (UserController.cs)
namespace SampleApplication.Controllers
{
public class UserController : Controller
{
public ActionResult User()
{
return View();
}
}
}
By using Data Annotations
In ASP.NET MVC one of the best ways to validate a model is by using Data Annotations. It has a set of attributes and classes defined in the System.ComponentModel.DataAnnotations assembly. Data Annotations allow us to decorate model classes with metadata. This metadata describes a set of rules that are used to validate a property.
For using DataAnnotations
, we need to add a reference to the System.ComponentModel.DataAnnotations assembly to model class.
using System.ComponentModel.DataAnnotations;
namespace SampleApplication.Models
{
public class UserModel
{
[Required(ErrorMessage = "Please Enter Name")]
[Display(Name = "Name")]
public string Name { get; set; }
[Required(ErrorMessage = "Please Enter Email Address")]
[Display(Name = "Email")]
[RegularExpression(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$",
ErrorMessage = "Please Enter Correct Email Address")]
public string Email { get; set; }
[Required(ErrorMessage = "Please Enter Mobile No")]
[Display(Name = "Mobile")]
[StringLength(10, ErrorMessage = "The Mobile must contains 10 characters", MinimumLength = 10)]
public string MobileNo { get; set; }
}
}
Now, we need to enable validationsummary
and to add validation message to view page.
The @Html.ValidationSummary()
method shows all the validation errors of a model in view page.
@Html.ValidationSummary(true)
@model SampleApplication.Models.UserModel
@{
ViewBag.Title = "User Details";
}
<br /><br />
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<legend>Form</legend>
<div class="form-group">
@Html.LabelFor(model => model.Name, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Email, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.Email, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Email)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.MobileNo, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.MobileNo, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.MobileNo)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="OK" />
</div>
</div>
</fieldset>
}
UserController.cs
namespace SampleApplication.Controllers
{
public class UserController : Controller
{
public ActionResult User()
{
return View();
}
[HttpPost]
public ActionResult ServerMeta(RegistrationMetaModel mRegister)
{
if (ModelState.IsValid)
{
return View("Completed");
}
else
{
return View();
}
}
}
}
By using ModelState object (Explicit Model Validation)
If you want to validate a model explicitly, then it is the best way to use ModelState
Object within ActionMethod
in controller. Just add an error message on ModelState
with (key, value) pair manner and that message will be shown on the view whenever the data will not be validated in the model.
Model
class will be shown as below:
namespace SampleApplication.Models
{
public class UserModel
{
public string Name { get; set; }
public string Email { get; set; }
public string MobileNo { get; set; }
}
}
Now we are going to add errormessage
to ModelState
object.
using System.Text.RegularExpressions;
using System.Web.Mvc;
using SampleApplication.Models;
namespace SampleApplication.Controllers
{
public class UserController : Controller
{
public ActionResult User()
{
return View();
}
[HttpPost]
public ActionResult User(UserModel model)
{
if (string.IsNullOrEmpty(model.Name))
{
ModelState.AddModelError("Name", "Please Enter Name");
}
if (!string.IsNullOrEmpty(model.Email))
{
string emailRegex = @"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$";
Regex re = new Regex(emailRegex);
if (!re.IsMatch(model.Email))
{
ModelState.AddModelError("Email", "Please Enter Correct Email Address");
}
}
else
{
ModelState.AddModelError("Email", "Please Enter Email Address");
}
if (string.IsNullOrEmpty(model.MobileNo))
{
ModelState.AddModelError("MobileNo", "Please enter your mobile no");
}
if (ModelState.IsValid)
{
return View("Completed");
}
else
{
return View();
}
}
}
}
The view User.cshtml will display the validation message is as follows:
@model SampleApplication.Models.UserModel
@{
ViewBag.Title = "User Details";
}
<br /><br />
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<legend>Form</legend>
<div class="form-group">
@Html.LabelFor(model => model.Name, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Email, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.Email, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Email)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.MobileNo, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.MobileNo, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.MobileNo)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="OK" />
</div>
</div> </fieldset>
}
By Using jQuery Validation Plug-in
The client side validation helps the application to reduce server loads and also it saves time of end user. So for client side validation, we are using following jQuery validation plug-in.
- jquery.validate.min.js
- jquery.validate.unobtrusive.min.js
Just add these files to your application if there are not present inside Scripts folder.
First of all, we need to add the following config setting in web.config file.
<appSettings>
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
In MVC4, the above appsetting is by default enabled in config file. But we need to ensure that the ClientValidationEnabled
and UnobtrusiveJavaScriptEnabled
value are true
before doing client side validation.
Now, we can write clientside
JavaScript code to validate data or by using DataAnnotations attributes in Model
.
Let's take advantage of DataAnnotations
API in client side validation. So add DataAnnotations
to model.
UserModel.cs
using System.ComponentModel.DataAnnotations;
namespace SampleApplication.Models
{
public class UserModel
{
[Required(ErrorMessage = "Please Enter Name")]
[Display(Name = "Name")]
public string Name { get; set; }
[Required(ErrorMessage = "Please Enter Email Address")]
[Display(Name = "Email")]
[RegularExpression(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$",
ErrorMessage = "Please Enter Correct Email Address")]
public string Email { get; set; }
[Required(ErrorMessage = "Please Enter Mobile No")]
[Display(Name = "Mobile")]
[StringLength(10, ErrorMessage = "The Mobile must contains 10 characters", MinimumLength = 10)]
public string MobileNo { get; set; }
}
}
UserController.cs
namespace SampleApplication.Controllers
{
public class UserController : Controller
{
public ActionResult User()
{
return View();
}
[HttpPost]
public ActionResult ServerMeta(RegistrationMetaModel mRegister)
{
if (ModelState.IsValid)
{
return View("Completed");
}
else
{
return View();
}
}
}
}
During MVC project creation, the application adds a BundleConfig.cs file under App_Start folder. This class is used to include scripts and styles in bundle.
Include validation plug-in to BundleCollection
object in BundleConfig.cs file.
The bundle code is:
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate*"));
The page template (_Layout.cshtml) created for a new MVC 4 project contains this code at the end of the page which does not pull in the jQuery validation library.
@RenderSection("scripts", required: false)
In order to "turn on" jQuery validation for a single view, the following code needs to reside at the end of view.
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
User.cshtml
@model SampleApplication.Models.UserModel
@{
ViewBag.Title = "User Details";
}
<br /><br />
@using (Html.BeginForm())
{
@Html.ValidationSummary(true)
<fieldset>
<legend>Form</legend>
<div class="form-group">
@Html.LabelFor(model => model.Name, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.Email, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.Email, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.Email)
</div>
</div>
<div class="form-group">
@Html.LabelFor(model => model.MobileNo, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
@Html.TextBoxFor(model => model.MobileNo, new { @class = "form-control" })
@Html.ValidationMessageFor(model => model.MobileNo)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="OK" />
</div>
</div> </fieldset>
}
@section Scripts {
@Scripts.Render("~/bundles/jqueryval")
}
By Using Fluent Validation Package
FluentValidation library provides some easy way to unit test validation rules, one can split the validation rules completely from the underlying model. Specially, it will be helpful when you need to inject dependencies into your validation rules.
Now we are going to use FluentValidation
class library by replacing DataAnnotations
from Model
.
Fluent Validation is available as a Nuget package, so search FluentValidation.MVC4
and install from Nuget Package Manager. After installing, you can find two new assemblies added to your application named as Fluent Validation and Fluent Validation.Mvc.
Add a new class called UserModelValidator
and place all the validation rules.
namespace SampleApplication.Models
{
public class UserModelValidator : AbstractValidator<UserModel>
{
public UserModelValidator()
{
RuleFor(x => x.Name)
.NotNull();
RuleFor(x => x.Email)
.NotNull()
.EmailAddress();
RuleFor(x => x.MobileNo)
.NotNull()
.Length(6, 10);
}
}
?}
Existing Model with DataAnnotations
using System.ComponentModel.DataAnnotations;
namespace SampleApplication.Models
{
public class UserModel
{
[Required(ErrorMessage = "Please Enter Name")]
[Display(Name = "Name")]
public string Name { get; set; }
[Required(ErrorMessage = "Please Enter Email Address")]
[Display(Name = "Email")]
[RegularExpression(@"^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$", ErrorMessage = "Please Enter Correct Email Address")]
public string Email { get; set; }
[Required(ErrorMessage = "Please Enter Mobile No")]
[Display(Name = "Mobile")]
[StringLength(10, ErrorMessage = "The Mobile must contains 10 characters", MinimumLength = 10)]
public string MobileNo { get; set; }
}
}
Now link UserModelValidator
validation class to the UserModel
class by specifying it in the Validator
attribute as follows:
[FluentValidation.Attributes.Validator(typeof(UserModelValidator))]
public class UserModel
{
[Display(Name = "Name")]
public string Name { get; set; }
[Display(Name = "Email")]
public string Email { get; set; }
[Display(Name = "Mobile")]
public string Mobileno { get; set; }
}
The last step is to call the FluentValidationModelValidatorProvider.Configure()
method inside your global.asax file.
namespace SampleApplication
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
FluentValidationModelValidatorProvider.Configure();
}
}
}
For more information about FluentValidation
, please refer to the following links:
The error messages are shown as below:
I have referred to the following links:
History
I will soon post the data-bind using AngularJS in MVC. Hope this helps beginners like me.