Data annotation in ASP.NET Core refers to the process of labeling the data that an application deal with. In other words, data annotations are attributes that are added to the properties which will let you enforce data input restrictions that might be necessary.

Data Annotations in ASP.NET Core

For instance, if it is a name field, you can specify it to accept only characters and the maximum number of characters that it can accept. Similarly, if there is an age field, you will be able to set the minimum and maximum age that the user can input for the value to be considered valid. The data again can be of any type, such as text, integer, double, or boolean.

There are three areas where you might be needed to use data annotations in your application. Those include:

Front-end validation attribute: This enables you to validate the data that the users would be required to input. For instance, using the front-end validation attribute, you can specify if a particular field must be filled up, set min and max limits, and so on.

Front-end display attributes: This will let you specify the manner the properties from your Model gets displayed on the screen for the user to see.

Back-end modeling attributes: This can be used to set table limitations as well as the relationships between classes. You can use back-end modeling attributes to set field type, mask, and such.

Data annotations can be found in the System.ComponentModel.DataAnnotations Namespace. Data annotations are specified inside square brackets with the option to include a single annotation in a code line or have a bunch of them separated by a comma in a single line.

Some of the most commonly used data annotations

MinLength and MaxLength: the length of the string that the user enters must be within the minimum and maximum limits as defined here.

Required: the particular field with this data annotation can’t be left empty.

Range: the user has to enter a numeric value that falls within the range as defined here.

Regular expression: the user must enter a value that must match a given format or a regular expression. This applies to those fields where the user is required to enter data such as an email address, social security number, phone numbers, zip codes, and so on.

Compare: this is applicable for those fields where you need to compare two strings, like say for password validation.

Display: Will allow you to set the label text.

DataType: this lets you determine how the output controls get rendered in the browser, like say for a password or an email.

Example of Data Annotations in ASP.NET Core

Here is an example code to demonstrate the above concept. For convenience, we consider here a simple application that is used to insert a book. The view includes fields for entering the Title, Author, Price, and Number of pages of the book.

    public class InsertBookViewModel
    {
        public string Title { get; set; }
        public string Author { get; set; }
        public int NumberOfPages { get; set; }
        public decimal Price { get; set; }
    }

The same code post addition of data annotations will look like the following:

    public class InsertBookViewModel
    {
        [Display(Prompt = "Enter title")]
        public string Title { get; set; }
        public string Author { get; set; }
        [Display(Name = "Number of pages")]
        public int NumberOfPages { get; set; }
        [Display(Name = "Price in USD")]
        public decimal Price { get; set; }
    }

At this point, it is important to keep in mind that the above data annotation will only allow for the basic form of data validation in the backend. For instance, it might be perfect for validating things like matching the password and so on. Unfortunately, the same won’t be enough for creating client-side validation or for forms where complex validations are required. In such cases, the validation will have to be part of the domain logic itself.

Meanwhile, our simple form of inserting books will have to be extended to include placeholders where the validation exception messages are going to be displayed. That is achieved using the HTML helper, ValidationMessageFor.

The Razor View

Here is how the code for the book insertion form will look like

@model DotNetCoreBookstore.Models.InsertBookViewModel
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Insert a new Book</title>
</head>
<body>
    <h1>Insert a new book</h1>
    @using (Html.BeginForm())
    {
        <div>
            @Html.LabelFor(m => m.Author)
            @Html.TextBoxFor(m => m.Author)
            @Html.ValidationMessageFor(m => m.Author)
        </div>
        <div>
            @Html.LabelFor(m => m.Title)
            @Html.TextBoxFor(m => m.Title)
            @Html.ValidationMessageFor(m => m.Title)
        </div>
        <div>
            @Html.LabelFor(m => m.Price)
            @Html.TextBoxFor(m => m.Price)
            @Html.ValidationMessageFor(m => m.Price)
        </div>
        <div>
            @Html.LabelFor(m => m.NumberOfPages)
            @Html.TextBoxFor(m => m.NumberOfPages)
            @Html.ValidationMessageFor(m => m.NumberOfPages)
        </div>
        <div>
            @Html.LabelFor(m => m.Genre)
            @Html.DropDownListFor(m => m.Genre, Html.GetEnumSelectList(typeof(DotNetCoreBookstore.Domains.Genre)))
        </div>
        <div>
            <input type="submit" name="create-book" value="Save" />
        </div>
    }
</body>
</html>

ViewModel Class

Here is the code for the book insertion view model post the addition of the data validation attributes:

    public class InsertBookViewModel
    {
        [Display(Prompt = "Enter title")]
        [Required(ErrorMessage = "The title is required"), MaxLength(10, ErrorMessage = "A book title cannot exceed 10 characters")]
        public string Title { get; set; }
        [Required(ErrorMessage = "The author is required"), MaxLength(15, ErrorMessage = "A book author cannot exceed 15 characters")]
        public string Author { get; set; }
        [Display(Name = "Number of pages")]
        [Required(ErrorMessage = "Number of pages is required"), Range(1, 10000, ErrorMessage = "Min pages: 1, max pages: 10000")]
        public int NumberOfPages { get; set; }
        [Required(ErrorMessage = "Enter a price"), Range(1, 1000, ErrorMessage = "Min price: 1, max price: 1000")]
        [Display(Name = "Price in USD")]
        public decimal Price { get; set; }
    }

However, the above code won’t be enough to prevent the insertion of an invalid book into the data store. Instead, all that the above will do is redirect you to the book index page. That is because data annotation can’t prevent the controller from executing its POST Create action method. The same can be taken care of, though, as is demonstrated in the following code.

As should be evident, the model state will know of any validation errors though the exceptions do not get applied on its own on the controller code.

Controller Function

    [HttpPost]
    [ValidateAntiForgeryToken]
    public IActionResult Create(InsertBookViewModel insertBookViewModel)
    {
        if (ModelState.IsValid)
        {
            _bookDAL _BookDAL;
            Book newBook = new Book()
            {
                Author = insertBookViewModel.Author,
                NumberOfPages = insertBookViewModel.NumberOfPages,
                Price = insertBookViewModel.Price,
                Title = insertBookViewModel.Title
            };
            _BookDAL.AddNew(newBook);
            return RedirectToAction("Index");
        }

        return View();

    }

This way, the user will be able to enter a book only when the model state is valid.

Summary

The above discourse introduced you to the concept of data annotations as well as how data annotations can be used to ensure only valid data gets saved in the data store. Data annotations aren’t a foolproof method of preventing invalid data from entering the datastore, though, but can serve as a guide for the users to enter the sort of data that is desired.

Related Articles

Last modified: October 14, 2019

Comments

Write a Reply or Comment

Your email address will not be published.