Validation

Sidenote : This is the part 11 of the ASP.Net MVC course series.  You can get all the parts of this tutorial here.

In our last chapter, we have saved movie information to the database. As we were not validating the data entered the user, there is a possibility of incorrect data getting saved to the database. To avoid this, we need to always validate the user input.

There are 2 types of validation based on where you validate the data

  1. Server side validation
  2. Client side validation

Server side validation:

When user submits the form with the data, you’ll receive the request in the controller. You can use the model to validate the user input. If there is no issue with the data, you can save the data to the database. If the input is not in correct format, you’ll not be saving the data. Instead, you’ll ask the user to enter the data in correct format.  User will enter the data in correct format again and the data can be saved to the database.

Server side validation

Client Side Validation:

You can validate few things at the client (browser) end itself. For example, if user has not entered title information, you can tell the user that she has to enter the data before submitting the form. There is no need to submit the form.

Client side validation

Client & Server Validation:

In most of the web applications, you’ll try to validate the data at the client side. If there is no issue at client side, then the request is submitted to the server where it may be validated further against the model. If the validation is successful, the data will be saved to the database. Else, inform the user that the data is invalid and ask her to enter the data in correct format.

Client Server side validation

 

 

First, we are going to do server side validation. Then we would use both client and server side validation as depicted in the last picture.

Enough theory. Let’s touch the code and do the changes required.

Validation is the process of comparing the entered data (or format) to the expected data (or format). So, first we need to define what correct data is? What is the expected format?

In our movie example, we can say Title field is required and year should be greater than 1900(as I’ve not seen any movie created before that).

Let us add this validation criteria to our Movie Model.

I have modified our Movie Model class like below.


using System.ComponentModel.DataAnnotations;

public int Id { get; set; }

 

[Required(ErrorMessage="Title of the movie is required")]

[MaxLength(100,ErrorMessage="Title can't be greater than 100 characters")]

public string Title { get; set; }

 

[Required(ErrorMessage="Release year is required")]

[Range(1900,2020, ErrorMessage="Year of release should be in between 1900 and 2020")]

public int Year { get; set; }

If you have not used Data Annotations before, above code may look bit scary.

Actually it’s pretty simple.

Let me explain.

‘Data annotations’ are attributes which provide metadata about our model classes. It tells more about your data – whether the data is required and if required how the data should be etc..

System.ComponentModel.DataAnnotations is the namespace where Data Annotations are defined. So we have to include that.

Let us take the data annotations that I have defined for Title field.


[Required(ErrorMessage="Title of the movie is required")]

[MaxLength(100,ErrorMessage="Title can't be greater than 100 characters")]

public string Title { get; set; }

[Required] data annotation tells that this property is required and this model object should not be allowed to be saved to the database with empty or absence of data. Even you can use data annotation like below without the error message. In this case, it will <Property> value is required – “Title value is required” in our case.


[Required]

public string Title { get; set; }

We would like to inform the user saying that this Title field is required. In case of user doesn’t give information about this field, we are saying an error message should displayed.


[Required(ErrorMessage="Title of the movie is required")]

public string Title { get; set; }

Above data annotation says that in the absence of Title data, the error message is set with the given value (“Title of the movie is required”). This error message can be sent to the user. And user would know what he has missed and he can enter the information (Title information in our case).

We have added another data annotation for the same Title property – Length . I have set the maximum length of the movie could be only of 100 characters. Exceeding that length, I am setting the error message which can be displayed to the user.

We are making Year as required property and setting the error message if it isn’t entered by the user. And I have added another data annotation – Range. This Range data annotation tells the possible range of values for the Year (from 1900 to 2020 in our case). If the user enters the year information outside of this range, error can be shown.


[Required(ErrorMessage="Release year is required")]

[Range(1900,2020, ErrorMessage="Year of release should be in between 1900 and 2020")]

public int Year { get; set; }

If you run the application after making the above changes, you’ll get error like below.

Model Change - Migration request error

 

It says that “There is a mismatch between your model class and the database table”. As we have added [Required] attribute to Title field, the respective Title column in Movies table in database also has to be updated as ‘Not null’ column.

By convention, types such as int, double would become ‘not null’ columns in the table in the database. String properties in class would be nullable columns in database. However, these conventions can be overridden.  See the movies table structure in the screenshot.

Id, primary key of int type, should not be null

Title, which is of string type, was made as nullable column

Year, int type, is not nullable column – That’s why you were getting 0 (default value for int type)in Year field when you ran the application.

Table structure

After adding data annotations, Entity framework expects the database structure would following properties

  1. Title column would have to be made ‘not null’
  2. We have defined maximum length of the column should be 100. So, instead of nvacrchar(max), it has to nvarchar(100) now.

 

As we have not changed anything in the database, there is a mismatch between our model definition and table definition. We can use ‘Database Migrations’ of Entity framework to sync the database tables with the model definition. You just have to do couple of steps

  1. You need to Enable database migrations
  2. Update the database as per the latest

Enabling database migrations:

Execute the command “Enable-Migrations –EnableAutomaticMigrations” in Package Manager Console. We are enabling the automatic migration so that Entity framework will take care of all changes.

 

 

 

Enable Migrations

 

A folder by name Migrations would be created with the configuration file.

Updating the database:

You need to tell Entity Framework to update the database as per the latest changes in the domain model.

“Update-Database” is the command that has to be executed in Package Manager Console.

But when I run that command, I get the following error.

 

Update Database - Error Data Loss

 

It says that if you do the database migrations – it will result in data loss. This is because of the change in the Title column length. Earlier, we didn’t restrict – it took the length as nvarchar(max). Now, we have restricted to 100 characters. So this may result in data loss.

And EF is giving few options for us.  I chose to set the AutomaticMigrationDataLossAllowed property to true. This means we are asking Migration to happen even if there is any data loss.

We have added the following line of code in Configuration class constructor in Migrations\Configuration.cs file

AutomaticMigrationDataLossAllowed = true;

When you execute the “Update-Database” again in Package Manager Console, the database table structure would be updated as per our latest model definition.

Movie Table structure after changes

See the Title column is made as ‘not null’ and max length 100.

Now, we need to check whether the user has entered the values in expected format/range.

Controller class (from which we inherit all of our application controllers) has ModelState property which tells whether the Model values that we received from the user is valid or not. If the model is valid, we can save the entered data to the database. Else, we can show the error message to the user so that he can change and submit the form with correct data again.


[HttpPost]

public ActionResult Add(Movie movieFromView)

{

if(ModelState.IsValid)

{

//Save the data in db and show the list of movies

using (var db = new MovieDBContext())

{

db.Movies.Add(movieFromView);

db.SaveChanges();

}

return RedirectToAction("Index");

}

return View(movieFromView);

}

We are verifying the model state in the Add action method by ModelState.IsValid property. If it’s valid, we are saving the data to the database (as we have done earlier). Else, we are returning the view again.

We just have to make one more change. We have to tell the view to show the error messages. @Html.ValidationMessageFor is the HTML helper method that we can make use of. This helper method would generate span element with data- attributes. Following is the HTML snippet generated for the Year field when you first access the form.


<span class="field-validation-valid" data-valmsg-for="Year" data-valmsg-replace="true"></span>

When you enter invalid value, say 9000 in Year filed, this span element would be converted as follows. Model error would be injected in this span element.


<span class="field-validation-error" data-valmsg-for="Year" data-valmsg-replace="true">Year of release should be in between 1900 and 2020</span>

The complete HTML razor code is attached below.


<div class="form-group">

@Html.LabelFor(m => m.Title, new { @class = "col-md-2 control-label" })

<div class="col-md-10">

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

@Html.ValidationMessageFor(m=>m.Title)

</div>

</div>

<div class="form-group">

@Html.LabelFor(m => m.Year, new { @class = "col-md-2 control-label" })

<div class="col-md-10">

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

<strong>            </strong>@Html.ValidationMessageFor(m => m.Year)

</div>

</div>

Now, run the application and give some invalid values. I have given Year value as 3000. But the accepted range is from 1900 to 2020. And I submit the form.

In Add action method, we are checking the validity of ModelState. As it is invalid, we are showing the same form with the error message. See the below screenshot.

Invalid movie

 

When you enter the values in expected range, the data would be saved to the database.

Everything seems to be fine. But there is a little problem here.

Why do we need to go for server, if the user did not any value for Title/Year?

We can find it out at the client end itself without going back to the server.

This is where the client side validation comes into picture.

We can use jQuery unobtrusive Validation to achieve this. Please note that this depends on jQuery library which should be available in your project.

You can get the jQuery Unobtrusive javascript by giving the following command in Package Manager Console.

“Install-Package Microsoft.jQuery.Unobtrusive.Validation”

 

 

PMC - jquery unobtrusive

 

Before installing, your script folder would be like this

Scripts folder b4 adding jquery unobstrusive

After installing, your script folder would contain additional javascript files like below

Scripts folder after adding jquery unobstrusive

You need to enable ClientValidation and Unobtrusive javascript in your Web.config file(in your root folder) like below


<appSettings>

<add key="webpages:Version" value="3.0.0.0" />

<add key="webpages:Enabled" value="false" />

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

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

</appSettings>

Add the respective javascript files in your Layout file(_Layout.cshtml in your Views/Shared folder) so that you can make use of client side validation in all of your views.


<script src="~/Scripts/jquery-1.10.2.min.js"></script>

<script src="~/Scripts/bootstrap.min.js"></script>

<script src="~/Scripts/jquery.validate.min.js"></script>

<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>

Now, run the application and access the http://localhost:1230/Movie/Add . Submit the form without entering the values. The values would be validated at the client side itself (without going to server) and the error messages would be shown.

Client Side validation Error

 

Previous Chapter Home Next Chapter [x_subscribe form=”398″]