How to use data annotations in C#

Take advantage of data annotations to decorate your models using attribute tags so that your application’s data definition can be managed in a single place

How to use data annotations in C#
Metamorworks / Getty Images

Data annotations (available as part of the System. ComponentModel. DataAnnotations namespace) are attributes that can be applied to classes or class members to specify the relationship between classes, describe how the data is to be displayed in the UI, and specify validation rules. This article talks about data annotations, why they are useful, and how to use them in our .NET Core applications.

To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here

Create a console application project in Visual Studio 2019

First off, let’s create a .NET Core Console Application project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new .NET Core Console Application project in Visual Studio.

  1. Launch the Visual Studio IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed.
  4. Click Next. 
  5. In the “Configure your new project” window shown next, specify the name and location for the new project.
  6. Click Create.

This will create a new .NET Core console application project in Visual Studio 2019. We’ll use this project to work with data annotations in the subsequent sections of this article.

Include the System. ComponentModel. DataAnnotations namespace

To work with the code samples given in this article, you should include the System. ComponentModel. DataAnnotations namespace in your program.

Note that attributes are used to specify metadata on a class or a property. The data annotation attributes can broadly be classified into the following:

  • Validation attribute — Used to enforce validation rules on the properties of the entities
  • Display attribute — Used to specify how the data should be displayed in the user interface
  • Modeling attribute — Used to specify the relationship that exists between classes

Data annotations attribute classes in C#

The System.ComponentModel.Annotations namespace comprises several attribute classes that can be used to define metadata for your entity classes or data controls. The most commonly used attributes include the following:

  • ConcurrencyCheck
  • Key
  • MaxLength
  • Required
  • StringLength
  • Timestamp

Data annotations example in C#

Create the following class in a file named Author.cs in the console application we’ve created earlier.

public class Author
    {
        [Required(ErrorMessage = "{0} is required")]
        [StringLength(50, MinimumLength = 3,
        ErrorMessage = "First Name should be minimum 3 characters and a maximum of 50 characters")]
        [DataType(DataType.Text)]
        public string FirstName { get; set; }
        [Required(ErrorMessage = "{0} is required")]
        [StringLength(50, MinimumLength = 3,
        ErrorMessage = "Last Name should be minimum 3 characters and a maximum of 50 characters")]
        [DataType(DataType.Text)]
        public string LastName { get; set; }
        [DataType(DataType.PhoneNumber)]
        [Phone]
        public string PhoneNumber { get; set; }
        [DataType(DataType.EmailAddress)]
        [EmailAddress]
        public string Email { get; set; }
    }

The following code snippet illustrates how you can create an instance of the Author class and assign values to its properties.

Author author = new Author();
author.FirstName = "Joydip";
author.LastName = "";
author.PhoneNumber = "1234567890";
author.Email = "joydipkanjilal@yahoo.com";

You can write the following code snippet in the Main method of the Program.cs file to validate your model.

ValidationContext context = new ValidationContext(author, null, null);
List<ValidationResult> validationResults = new List<ValidationResult>();
bool valid = Validator.TryValidateObject(author, context, validationResults, true);
if (!valid)
{
  foreach (ValidationResult validationResult in validationResults)
  {
       Console.WriteLine("{0}", validationResult.ErrorMessage);
  }
}

ValidationContext is the class that provides you the context where the validation should be done. The TryValidateObject static method of the Validator class returns true if the validation is successful, false otherwise. It also returns a list of ValidationResults that details all validations that have failed on the model. Finally, we’ve used a foreach loop to iterate the list of ValidationResults and display the error messages at the console window.

The complete code listing is given below for your reference.

public class Author
    {
        [Required(ErrorMessage = "{0} is required")]
        [StringLength(50, MinimumLength = 3,
        ErrorMessage = "First Name should be minimum 3 characters and a maximum of 50 characters")]
        [DataType(DataType.Text)]
        public string FirstName { get; set; }
        [Required(ErrorMessage = "{0} is required")]
        [StringLength(50, MinimumLength = 3,
        ErrorMessage = "Last Name should be minimum 3 characters and a maximum of 50 characters")]
        [DataType(DataType.Text)]
        public string LastName { get; set; }
        [DataType(DataType.PhoneNumber)]
        [Phone]
        public string PhoneNumber { get; set; }
        [DataType(DataType.EmailAddress)]
        [EmailAddress]
        public string Email { get; set; }
    }
    class Program
    {      
        static void Main(string[] args)
        {
            Author author = new Author();
            author.FirstName = "Joydip";
            author.LastName = ""; //No value entered
            author.PhoneNumber = "1234567890";
            author.Email = "joydipkanjilal@yahoo.com";
            ValidationContext context = new ValidationContext
            (author, null, null);
            List<ValidationResult> validationResults = new
            List<ValidationResult>();
            bool valid = Validator.TryValidateObject
            (author, context, validationResults, true);
            if (!valid)
            {
                foreach (ValidationResult validationResult in
                validationResults)
                {
                    Console.WriteLine("{0}",
                    validationResult.ErrorMessage);
                }
            }
            Console.ReadKey();
        }
    }

When you execute the program, you should see the following error message displayed at the console window:

LastName is required

Create a custom validation attribute in C#

To create a custom validation attribute class, you should extend the ValidationAttribute base class and override the IsValid method as shown in the code snippet given below.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class IsEmptyAttribute : ValidationAttribute
 {
    public override bool IsValid(object value)
     {
         var inputValue = value as string;
         return !string.IsNullOrEmpty(inputValue);
     }
 }

The following code snippet illustrates how you can use the custom attribute to decorate the FirstName and LastName properties of the Author class.

[IsEmpty(ErrorMessage = "Should not be null or empty.")]
public string FirstName { get; set; }
[IsEmpty(ErrorMessage = "Should not be null or empty.")]
public string LastName { get; set; }

Data annotations were introduced initially in .NET 3.5 as part of the System. ComponentModel. DataAnnotations namespace. Since then they have become a widely used feature in .NET. You can take advantage of data annotations to define data validation rules in a single place and thereby avoid having to re-write the same validation code again and again.

In a future post here, we’ll look at how data annotation can be used in ASP.NET Core MVC applications to perform model validation.

How to do more in C#

Copyright © 2020 IDG Communications, Inc.