Model Validations in ASP.NET Core MVC

Model Validations in ASP.NET Core MVC

In this article, I will discuss Model Validations in ASP.NET Core MVC with Examples. Please read our previous article discussing Data Annotations in ASP.NET Core MVC.

Why do we Need Data Annotation Attributes in ASP.NET Core MVC?

Nowadays, it’s challenging for a web developer to validate the user input for any Web application. As web developers, we not only validate the business data on the client side, i.e., in the browser, but we also need to validate the business data on the server side. That means, as a developer, we need to validate the business data both at the client and server sides.

The client-side validation gives the users immediate feedback on the information they entered into a web page, which is an expected feature in today’s web applications. Along the same line, the server-side validation is in place because we never trust the information from the network. 

What are Validations?

Validations in a website refer to the processes and rules that ensure data entered by users meets specific criteria before being processed. The main purpose of validations is to maintain data integrity, enhance user experience, and secure the website against malicious inputs. There are two types of validations:

  • Server-Side Validations
  • Client-Side Validations
Client-Side Validation:
  • Occurs in the user’s browser.
  • Uses JavaScript (or similar client-side scripting languages) to validate data before it’s sent to the server.
  • It provides a responsive user experience because validation feedback is immediate, without requiring a round trip to the server.
  • We should never solely depend on client-side validations since users can bypass or manipulate client-side scripts.
Server-Side Validation:
  • It occurs on the web server after the data is sent from the client’s browser.
  • Uses server-side scripting languages (like C#, Java, Python, PHP, etc.) to validate the data before processing it or saving it to a database.
  • It is essential because it’s the last defense against incorrect or malicious data.

While doing validations, as a developer, we need to take care of the proper validation and ensure that the validation meets the business rule as per the requirement. From the security point of view, it is also possible that some hackers may bypass client-side validation and insert some vulnerable data into the server.

Validations in ASP.NET Core MVC Web Applications:

We primarily focus on validating the model value when discussing the ASP.NET Core MVC framework validation. That means has the user provided a required value? Is the value in the required range? Is the value in a proper format, etc.?

In ASP.NET Core MVC Web Applications, we can do the following three types of validations:

  • HTML Validation / JavaScript Validation (i.e. Client-Side Validation)
  • ASP.NET Core MVC Model Validation (i.e. Server-Side Validation)
  • Database Validation (i.e., Server-Side Validation)

Among the above three, ASP.NET Core MVC Model Validation is the most secure validation. In HTML/JavaScript Validation, the validation can break easily by disabling the JavaScript in the client machine, but the model validation can’t break.

ASP.NET Core MVC Framework provides a concept called Data Annotation used for model validation. It’s inherited from the System.ComponentModel.DataAnnotations assembly.

The ASP.NET Core MVC Framework uses Data Annotation attributes to implement model validations. The Data Annotation Attributes include built-in validation attributes for different validation rules, which can be applied to the model class properties.

The ASP.NET Core MVC framework will automatically enforce the validation rules and then display proper validation messages in the view if validation fails.

Note: Apart from Data Annotation, we can also use Fluent API Validations, which gives more control over Data Annotation.

Common Validation Scenarios Encountered on a Websites:

The following are the common validation scenarios encountered in a website.

  • Required Fields: Ensuring that mandatory fields are filled in before form submission.
  • Data Type Validation: Verifying that data entered is of the correct type, e.g., numbers, text, dates.
  • Range Validation: Checking if a numeric value falls within a certain range. For instance, age should be between 18 and 60.
  • Format Validation: Verifying if data matches a particular format, e.g., email addresses, phone numbers, and postal codes.
  • Consistency Check: Ensuring that data across multiple fields is consistent. For instance, the “Confirm Password” field should match the “Password” field. Another example you can take when entering the Credit Card Number.
  • Custom Business Rules: Certain validations might be unique depending on the application’s business logic. For example, a flight booking system might validate that the return date is after the departure date.
  • Blacklist Checks: This involves checking inputs against known malicious or undesired inputs. It’s a basic defense against code injection attacks. Suppose you want to restrict some of the characters entered on a field.
  • Whitelist Checks: Only allowing a specific set of values or patterns for an input. It’s generally more secure than blacklist checks because it’s restrictive. It is just the opposite of Blacklist Checks.
  • Size Limit Checks: Ensuring data, especially uploaded files, don’t exceed a certain size. When entering an image, you need to set the size of the image.
  • CAPTCHAs: To validate that the user is a human, not a bot.

For a secure and user-friendly website, it’s crucial to have both client-side and server-side validations. Client-side validation enhances user experience by providing immediate feedback, while server-side validation ensures that malicious or incorrect data does not compromise the system. Remember that client-side validation can be easily bypassed, so never rely on it for security or data integrity.

System.ComponentModel.DataAnnotations Attributes:

The System.ComponentModel.DataAnnotations assembly has many built-in validation attributes, for example:

  • Required: Specifies the field is required
  • Range: Specifies the minimum and maximum value allowed
  • MinLength: Specifies the minimum length of a string
  • MaxLength: Specifies the maximum length of a string
  • Compare: Compares 2 properties of a model. For example, compare Email and ConfirmEmail properties
  • RegularExpression: Validates if the provided value matches the pattern specified by the regular expression

Along with the above build-in validation attributes, there are also many data types the user can select to validate the input. Using this data type attribute, the user can validate the exact data type as in the following:

  • Credit Card number
  • Currency
  • Custom
  • Date
  • DateTime
  • Duration
  • Email Address
  • HTML
  • Image URL
  • Multiline text
  • Password
  • Phone number
  • Postal Code
  • Upload
Example to Understand Model Validation in ASP.NET Core MVC

Let us understand Model Validation in ASP.NET Core MVC Application using Data Annotations with a simple example. So, we want to create the following Create Employee Form.

Model Validations in ASP.NET Core MVC with Examples

We want to make the Name, Email, and Department fields required. If the required values are not provided and the form is submitted, we want to display the required validation errors, as shown in the image below.

Model Validations in ASP.NET Core MVC with Examples

If we enter an Invalid Email, it should display an Invalid Email Format validation error, as shown below.

Example to Understand Model Validation in ASP.NET Core MVC

Let us proceed and see how we can implement this using Data Annotation Attributes in ASP.NET Core MVC Application.

Creating the Model with Data Annotation Attributes:

Create a class file named Department.cs, then copy and paste the following code. As you can see, this will be an Enum, and these Enum constants will be the data source for our department field.

namespace DataAnnotationsDemo.Models
{
    public enum Department
    {
        None,
        HR,
        Payroll,
        IT
    }
}

Next, create another class file named Empoyee.cs, and then copy and paste the following code. As you can see in the code below, we have marked Name, Email, and Department properties with the Required Attribute, which makes these properties required while doing the model validation. The Required Data Annotation Attribute belongs to the System.ComponentModel.DataAnnotations namespace.

using System.ComponentModel.DataAnnotations;
namespace DataAnnotationsDemo.Models
{
    public class Employee
    {
        public int Id { get; set; }
        [Required]
        public string Name { get; set; }
        [Required]
        public string Email { get; set; }
        [Required]
        public Department? Department { get; set; }
    }
}
Creating Employee Controller:

Create a new Empty – MVC Controller with the name EmployeeController and then copy and paste the following code into it.

using DataAnnotationsDemo.Models;
using Microsoft.AspNetCore.Mvc;

namespace DataAnnotationsDemo.Controllers
{
    public class EmployeeController : Controller
    {
        public IActionResult Create()
        {
            return View();
        }

        [HttpPost]
        public IActionResult Create(Employee employee)
        {
            //Check if the Model State is Valid
            if (ModelState.IsValid)
            {
                //Save the Data into the Database
                //Redirect to a Different View
                return RedirectToAction("Successful");
            }

            //Return to the same View and Display Model Validation error
            return View();
        }

        public string Successful()
        {
            return "Employee Addedd Successfully";
        }
    }
}
Explanation:
  • In our example, the Create() action method, decorated with HTTP Post Attribute, will be executed when the form is submitted.
  • The model for the Create Employee Form is the Employee class, and when the form is submitted, model binding maps the posted form values to the respective properties of the Employee class.
  • With the Required attribute on the Name, Email, and Department properties of the Employee class, if a value for the Name, Email, and Department properties is not present, the model validation fails.
  • We need to use ModelState.IsValid property to check if validation has failed or succeeded.
  • If validation has failed, we return the same view so the user can provide the required data and resubmit the form.
  • If there is no validation error, we often save the data into the database and then redirect to a different view as per the business requirement.
Displaying Model Validation Error in ASP.NET Core MVC Razor Views:

We must use asp-validation-for and asp-validation-summary tag helpers to display model validation errors on ASP.NET Core Razor Views. The asp-validation-for tag helper displays a validation message for a single property of our model class. On the other hand, the asp-validation-summary tag helper summarizes all validation errors that occurred on a model.

For example, to display the validation error associated with the Name property of the Employee class, we need to use asp-validation-for tag helper on a <span> element, as shown below.

<div class="form-group row">
    <label asp-for="Name" class="col-sm-2 col-form-label"></label>
    <div class="col-sm-10">
        <input asp-for="Name" class="form-control" placeholder="Enter Your Name">
        <span asp-validation-for="Name"></span>
    </div>
</div>

On the other hand, to display a summary of all validation errors, we need to use the asp-validation-summary tag helper on a <div> element, as shown below.

<div asp-validation-summary="All" class="text-danger"></div>

The value for the asp-validation-summary tag helper can be any of the following.

  • All
  • ModelOnly
  • None

In our upcoming article, we will discuss the difference between these values and what they do. For now, please set it to a value of All.

By default, it will show the error message in black color. If you want to display the error message in red, use the bootstrap class=”text-danger” as follows.

<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group row">
    <label asp-for="Name" class="col-sm-2 col-form-label"></label>
    <div class="col-sm-10">
        <input asp-for="Name" class="form-control" placeholder="Enter Your Name">
        <span asp-validation-for="Name" class="text-danger"></span>
    </div>
</div>
Creating ASP.NET Core Razor Views to Display Error Messages:

Next, create a view for the Create action method of Employee Controller. Once you add the Create.cshtml view file, please copy and paste the following code.

@model DataAnnotationsDemo.Models.Employee

@{
    ViewData["Title"] = "Create";
}

<h1>Create Employee</h1>

<div class="row">
    <form asp-controller="Employee" asp-action="Create" method="post" class="mt-3">
        <div asp-validation-summary="All" class="text-danger"></div>
        <div class="form-group row">
            <label asp-for="Name" class="col-sm-2 col-form-label"></label>
            <div class="col-sm-10">
                <input asp-for="Name" class="form-control" placeholder="Enter Your Name">
                <span asp-validation-for="Name" class="text-danger"></span>
            </div>
        </div>
        <div class="form-group row">
            <label asp-for="Email" class="col-sm-2 col-form-label"></label>
            <div class="col-sm-10">
                <input asp-for="Email" class="form-control" placeholder="Enter Your Email">
                <span asp-validation-for="Email" class="text-danger"></span>
            </div>
        </div>

        <div class="form-group row">
            <label asp-for="Department" class="col-sm-2 col-form-label"></label>
            <div class="col-sm-10">
                <select asp-for="Department" class="form-select" 
                        asp-items="Html.GetEnumSelectList<Department>()">
                    <option value="">Please Select</option>
                </select>
                <span asp-validation-for="Department" class="text-danger"></span>
            </div>
        </div>

        <div class="form-group row">
            <div class="col-sm-10">
                <button type="submit" class="btn btn-primary">Create</button>
            </div>
        </div>
    </form>
</div>

Now, run the application, navigate to /Employee/Create URL, and submit the form without filling in any data, and you will see the following error messages.

Creating ASP.NET Core Razor Views to Display Error Messages

Customizing Model Validation Error Message in ASP.NET Core MVC

By default, the Required attribute on the Name, Email, and Department properties displays the validation error messages we have seen in our previous example.

  • The Name field is required.
  • The Email field is required.
  • The Department field is required.

If you want to customize the validation error message, use the ErrorMessage property of the Required attribute. So, modify the Employee model class as shown below to display some user-friendly error message when the user submits the form without providing values for these fields.

using System.ComponentModel.DataAnnotations;
namespace DataAnnotationsDemo.Models
{
    public class Employee
    {
        public int Id { get; set; }
        [Required(ErrorMessage = "Please Enter the First Name")]
        public string Name { get; set; }
        [Required(ErrorMessage = "Please Enter the Email Address")]
        public string Email { get; set; }
        [Required(ErrorMessage = "Please Select the Department")]
        public Department? Department { get; set; }
    }
}

With the above model changes, run the application, navigate to /Employee/Create URL, and submit the form without filling in any data. You will see the following custom error messages as expected.

Customizing Model Validation Error Message in ASP.NET Core MVC

Using Multiple Model Validation Attributes:

It is also possible in ASP.NET Core to apply multiple validation attributes on a single property. For example, we have only applied the Required Attribute with the Email Property. So, in this case, it will only check whether you are providing any value for the Email Field. It is not going to check whether the entered value is in a proper format or not. So, if you enter anything and submit the form, it will not give you any error message, as shown in the below image.

Using Multiple Model Validation Attributes

Along with the Required Validation, we also want to apply the Invalid Format error message for the Email ID field. We must use either the EmailAddress Attribute or RegularExpression attribute to achieve this along with the Required Attribute. So, modify the Employee class as follows.

using System.ComponentModel.DataAnnotations;
namespace DataAnnotationsDemo.Models
{
    public class Employee
    {
        public int Id { get; set; }
        [Required(ErrorMessage = "Please Enter the First Name")]
        public string Name { get; set; }
        [Required(ErrorMessage = "Please Enter the Email Address")]
        //[EmailAddress(ErrorMessage = "Please Enter a Valid Email")]
        [RegularExpression(@"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$",
            ErrorMessage = "Please Enter a Valid Email")]
        public string Email { get; set; }
        [Required(ErrorMessage = "Please Select the Department")]
        public Department? Department { get; set; }
    }
}

With the above changes in place, run the application, navigate to the /Employee/Create URL, and submit the form by entering an invalid email address. You should get the appropriate error message, as shown in the below image.

Using Multiple Model Validation Attributes

Currently, the Validation is performed on the server side, not the client side. The Validation attributes in ASP.NET MVC Framework provide both client-side and server-side validation. Let us proceed and understand how to enable client-side validation in ASP.NET Core MVC.

Enabling Client-Side Validation in ASP.NET Core MVC:

Client-side validation in ASP.NET Core MVC Application is a feature that allows us to perform validation on the client browser without making a round trip to the server. This provides a more responsive experience for the user.

ASP.NET Core MVC uses jQuery Validation and jQuery Unobtrusive Validation for client-side validation. Here’s how you can enable client-side validation in an ASP.NET Core MVC application:

You must include jQuery, jQuery Validation, and jQuery Unobtrusive Validation in your project. These can be added via CDNs or local files. For example, include them via CDNs in your _Layout.cshtml:

<!-- jQuery -->
<script src="https://code.jquery.com/jquery-3.5.1.min.js"></script>

<!-- jQuery Validation Plugin -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.2/jquery.validate.min.js"></script>

<!-- jQuery Unobtrusive Validation (to bridge ASP.NET Core MVC validation with jQuery Validate) -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script>

Please add the following files in your _Layout.cshtml to enable client-side validation using local files. The order is also important, and please include them in the following order.

<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

The order in which the script files are referenced is also important. jquery.validate is dependent on jquery, and /jquery.validate.unobtrusive is dependent on jquery.validate, so they should be referenced in the above order. Otherwise, client-side validation will not work as expected. In short, JavaScript is parsed “top-down”, so all dependencies must be referenced before the dependent reference.

With these changes in place, the client-side validation should be active in your ASP.NET Core MVC application. Whenever a user attempts to submit the form, jQuery Validation will check input values against the data annotations before the form is submitted. If validation fails, appropriate error messages will be displayed next to the form fields. However, always validate on the server side since client-side validation can be bypassed.

Best Practices to Use Validation Related JavaScript files:

We must include the following three JavaScript files in our Layout File to enable Client-Side Validation using Data Annotation.

<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

The point that you need to remember is we are not going to create forms, and we are not going to do client-side validations on each and every web page of our application. If we include the above JavaScript files inside our Layout files, they will be downloaded on every page where we use the layout file, even if we are not performing client-side validations.

Creating a Partial View:

So, to overcome this problem, let us create a partial view with the name _ValidationScriptsPartial.cshtml within our application’s Views/Shared folder and then copy and paste the following code into it. We are not including the jquery.js file because the jQuery.js file is required in all the pages, and hence, it is better to put that file inside the layout file.

<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>

Next, we must add a render section inside the layout file to include the partial view above. So, add the following code just before the end of the body tag of the layout file.

@await RenderSectionAsync("ValidationScripts", required: false)

This is the place where we need to add the validation script. Suppose our Create.cshtml view wants client-side validation; then, we need to add the following code just before the end of the view.

@section ValidationScripts {
    @{
        await Html.RenderPartialAsync("_ValidationScriptsPartial");
    }
}

With these changes in place, run the application, and you will see that the client-side validation is working as expected.

Using HTML Helper to Provide Validation Message:

Instead of using asp-validation-summary and asp-validation-for tag helpers, we can also use Html.ValidationSummary and Html.ValidationMessageFor html helper methods to achieve the same. So, modify the Create.cshtml file as shown below to use HTML helper methods to display the error message.

@model DataAnnotationsDemo.Models.Employee

@{
    ViewData["Title"] = "Create";
}

<h1>Create Employee</h1>

<div class="row">
    <form asp-controller="Employee" asp-action="Create" method="post" class="mt-3">
        @*<div asp-validation-summary="All" class="text-danger"></div>*@
        <div class="text-danger">
            @Html.ValidationSummary()
        </div>
        <div class="form-group row">
            <label asp-for="Name" class="col-sm-2 col-form-label"></label>
            <div class="col-sm-10">
                <input asp-for="Name" class="form-control" placeholder="Enter Your Name">
               @* <span asp-validation-for="Name" class="text-danger"></span>*@
                <span class="text-danger">
                    @Html.ValidationMessageFor(x => x.Name)
                </span>
            </div>
        </div>
        <div class="form-group row">
            <label asp-for="Email" class="col-sm-2 col-form-label"></label>
            <div class="col-sm-10">
                <input asp-for="Email" class="form-control" placeholder="Enter Your Email">
               @* <span asp-validation-for="Email" class="text-danger"></span>*@
                <span class="text-danger">
                    @Html.ValidationMessageFor(x => x.Email)
                </span>
            </div>
        </div>

        <div class="form-group row">
            <label asp-for="Department" class="col-sm-2 col-form-label"></label>
            <div class="col-sm-10">
                <select asp-for="Department" class="form-select" 
                        asp-items="Html.GetEnumSelectList<Department>()">
                    <option value="">Please Select</option>
                </select>
                @*<span asp-validation-for="Department" class="text-danger"></span>*@
                <span class="text-danger">
                    @Html.ValidationMessageFor(x => x.Department)
                </span>
            </div>
        </div>

        <div class="form-group row">
            <div class="col-sm-10">
                <button type="submit" class="btn btn-primary">Create</button>
            </div>
        </div>
    </form>
</div>

@section ValidationScripts {
    @{
        await Html.RenderPartialAsync("_ValidationScriptsPartial");
    }
}

In the next article, I will discuss How to Perform Model Validations using Data Annotation Attributes in ASP.NET Core MVC Application with Examples. In this article, I try to explain Model Validations in ASP.NET Core MVC with Examples. I hope you enjoy this Model Validations in ASP.NET Core MVC article.

Leave a Reply

Your email address will not be published. Required fields are marked *