How to use data annotations in C#

By FoxLearn 1/6/2025 4:02:45 AM   102
Data annotations are attributes from the `System.ComponentModel.DataAnnotations` namespace that can be applied to classes or class members.

Data annotation attributes include:

  • Validation attributes - Enforce validation rules on entity properties.
  • Display attributes - Define how data should be displayed in the user interface.
  • Modeling attributes - Specify relationships between classes.

Data annotations attribute classes in C#

The System.ComponentModel.DataAnnotations namespace contains several attribute classes used to define metadata for entity classes or data controls. Some of the most commonly used attributes include:

  • ConcurrencyCheck - Ensures data concurrency control.
  • Key - Specifies the primary key of an entity.
  • MaxLength - Sets the maximum length for a string property.
  • Required - Marks a property as mandatory.
  • StringLength - Specifies the allowable length range for a string property.
  • Timestamp - Used for versioning and concurrency checks.

Example of Data Annotations in C#

Create a Product.cs class with data annotations for validation:

public class Product
{
    [Required(ErrorMessage = "{0} is required")]
    [StringLength(100, MinimumLength = 3, ErrorMessage = "Product Name should be between 3 and 100 characters")]
    [DataType(DataType.Text)]
    public string ProductName { get; set; }

    [Range(0.01, 10000.00, ErrorMessage = "Price must be between $0.01 and $10,000")]
    [DataType(DataType.Currency)]
    public decimal Price { get; set; }

    [Required(ErrorMessage = "{0} is required")]
    [StringLength(200, MinimumLength = 10, ErrorMessage = "Description should be between 10 and 200 characters")]
    public string Description { get; set; }

    [DataType(DataType.Date)]
    public DateTime ManufactureDate { get; set; }
}

Create an instance of the Product class and validate it:

Product product = new Product();
product.ProductName = "Laptop";
product.Price = 1200.00;
product.Description = "A high-performance laptop.";
product.ManufactureDate = DateTime.Now;

ValidationContext context = new ValidationContext(product, null, null);
List<ValidationResult> validationResults = new List<ValidationResult>();
bool valid = Validator.TryValidateObject(product, context, validationResults, true);

if (!valid)
{
    foreach (ValidationResult validationResult in validationResults)
    {
        Console.WriteLine("{0}", validationResult.ErrorMessage);
    }
}

If you run the program with an invalid Price value (e.g., 0), it will display an error:

Price must be between $0.01 and $10,000

Custom Validation Attribute in C#

To create a custom validation attribute in C#, you can extend the ValidationAttribute base class and override the IsValid method.

[AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = false)]
public class RangeValidationAttribute : ValidationAttribute
{
    private readonly int _minValue;
    private readonly int _maxValue;

    public RangeValidationAttribute(int minValue, int maxValue)
    {
        _minValue = minValue;
        _maxValue = maxValue;
    }

    public override bool IsValid(object value)
    {
        if (value is int inputValue)
        {
            return inputValue >= _minValue && inputValue <= _maxValue;
        }
        return false;
    }
}

In this example, we apply the custom RangeValidationAttribute to a Quantity property in a Product class. This ensures the value is between 1 and 100.

public class Product
{
    [Required(ErrorMessage = "Product Name is required")]
    public string ProductName { get; set; }

    [RangeValidation(1, 100, ErrorMessage = "Quantity must be between 1 and 100")]
    public int Quantity { get; set; }

    [Required(ErrorMessage = "Price is required")]
    public decimal Price { get; set; }
}

Here’s how you can validate an instance of the Product class:

Product product = new Product
{
    ProductName = "Laptop",
    Quantity = 150, // Invalid value
    Price = 1200.00
};

ValidationContext context = new ValidationContext(product, null, null);
List<ValidationResult> validationResults = new List<ValidationResult>();
bool isValid = Validator.TryValidateObject(product, context, validationResults, true);

if (!isValid)
{
    foreach (ValidationResult validationResult in validationResults)
    {
        Console.WriteLine(validationResult.ErrorMessage);
    }
}

Custom validation attributes allow you to enforce more complex validation rules within your classes. By extending ValidationAttribute and overriding the IsValid method, you can create reusable and customizable validation logic for various types of data.