DEV Community

Cover image for Data Annotations in C#: Your Complete Guide
ByteHide
ByteHide

Posted on • Originally published at bytehide.com

Data Annotations in C#: Your Complete Guide

Let’s be sincere, we’ve all faced challenges while managing data in C#, haven’t we? But what if I told you there’s a tool in C# that might help you with data validation effectively? Yes, you guessed it! Our topic of interest today is data annotations in C#. Let’s dive in and explore this amazing feature together.

Understanding Data Annotations in C#

“We are not just dealing with code; we need to communicate in a language users understand!” Have you ever uttered these words? That’s exactly what they are for ‘Display Name Annotations’.

Display Name Data Annotation in C# brings the amazing possibility of customizing display names for your data. It’s an ideal way to tailor your data presentation according to user-friendly terms rather than tech jargon.

The Essentials of C# Data Annotations

Data annotations in C# are like power-ups for your code. They handle and authenticate data efficiently, making your development process smoother. In simpler terms, data annotations are attributes you can place on a class definition in the .NET Framework.

They add context and behavior, allowing the .NET runtime to execute additional processing such as providing validation around fields, properties, and classes. These annotations have a wide range of applications and benefits.

public class Order
{
    [Key]
    public int OrderID { get; set; }

    [Required(ErrorMessage = "CustomerName is required")]
    [StringLength(100, ErrorMessage = "CustomerName cannot be longer than 100 characters")]
    public string CustomerName { get; set; }

    [RegularExpression(@"^\d+.?\d{0,2}$", ErrorMessage = "Invalid total")]
    [Range(1, 500, ErrorMessage = "Total must be between 1 and 500")]
    public decimal Total { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

In this code snippet, the Order class has three properties: OrderID, CustomerName and Total.

The [Key] annotation is placed on the OrderID property, earmarking it as a unique identifier. The [Required] and [StringLength] annotations applied to the CustomerName property ensure the field is not empty and its size doesn’t exceed 100 characters.

The [RegularExpression] and [Range] annotations on Total enforce number-specific validation.

Display Name Data Annotation in C#

C# data annotations offer customization options as well. Display names of data properties can be tailored to the programmer’s needs. Ever wondered if you could make data property names more user-friendly, or standardize them across your entire application? You will be glad to learn that with ‘display name data annotation in C#,’ that’s absolutely possible.

Consider a scenario where you are developing a Human Resources application. The users are HR experts, not necessarily tech-savvy or familiar with programmer jargon. It would be much friendlier to present ‘Employee ID’ instead of ‘EmpID’, wouldn’t it? Here’s how to implement it with data annotations:

public class Employee
{
    // Customizes the display name for the property
    [Display(Name = "Employee ID")]
    public string EmpID{ get; set; }

    [Display(Name = "Date of Joining")]
    public DateTime DoJ{ get; set; }

    [Display(Name = "Is Permanent Employee")]
    public bool IsPermanent { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

In the code above, we’ve used the Display attribute to provide user-friendly text for the EmpID, DoJ, and IsPermanent properties. So, instead of displaying the bare property name of ‘EmpID’, ‘DoJ’, and ‘IsPermanent’, the end-user will see the meaningful and user-friendly labels ‘Employee ID’, ‘Date of Joining’, and ‘Is Permanent Employee’.

Maximizing the Use of Maxlength Data Annotation in C#

Many troubles can arise while entering data, and sometimes, these may trace back to a quite simple mistake––like typing too many characters. It may sound trivial, but such issues, if left unresolved, can harm the executable program during runtime and even hinder the user experience considerably.

However, fret not. Luckily, the ‘maxlength data annotation in C#’ is here to save us all. This feature is straightforward but highly effective, assuring that your data stays within the set boundaries. It restricts the maximum length of a string and helps prevent potential overflow and validation errors.

Definitely, ‘maxlength data annotation in C#’ is a tool we should all master, and guess what? The learning curve is rather gentle!

Applying MaxLength Data Annotation in C#

How about we roll up our sleeves and dig a bit deeper into ‘maxlength data annotation in C#’ with some practical examples? Surely, there’s no better way to learn than a hands-on approach, right?

Starting with a classic–validate username input in a registration form. You don’t want your users to go wild with their usernames, do you? Let’s impose a limit of 20 characters for usernames. Here’s how:

public class Registration
{
    [MaxLength(20, ErrorMessage = "Username cannot exceed 20 characters")]
    public string UserName { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

As seen above, the ‘MaxLength’ annotation is being used to limit the UserName field to a maximum of 20 characters. If any eager user tries to register with a longer username, the attribute will trigger the error message.

But wait, there’s more. Let’s consider another example – a product code. Every product has a unique code. However, for simplicity in inventory management, you don’t want codes that are over 10 characters long. With ‘MaxLength’ data annotation, you can again enforce this rule with ease:

public class Product
{
    [MaxLength(10, ErrorMessage = "Product code cannot be longer than 10 characters")]
    public string ProductCode { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

In this case, the annotation ensures that the ProductCode value contains a maximum of 10 characters, enforcing the rule consistently throughout your application. If anyone attempts to enter a code exceeding 10 characters, the system will stop them with the pre-set error message.

Not just input fields, ‘maxlength data annotation in C#’ also becomes particularly handy when working with databases. Ensuring your string length matches your database schema can prevent runtime exceptions and maintain data integrity. Here’s how you can do it:

public class Employee
{
    [MaxLength(30, ErrorMessage = "Employee names should be within 30 characters")]
    public string EmployeeName { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

In this example, EmployeeName is restricted to 30 characters, ensuring it matches the corresponding database column’s length. If any name longer than 30 characters is attempted to be saved, it’ll raise a red flag.

The use of ‘maxlength data annotation in C#’ does not stop at restricting user inputs or maintaining database integrity. It extends to enhancing performance by lowering memory consumption and assisting in faster data retrieval. By restricting the length of data, you end up storing only what is necessary, thus enhancing your application’s overall performance.

Therefore, ‘maxlength data annotation in C#’ is a way of weaving commandments into your data models. It’s a good practice to get into. It “keeps your characters in character”, so to speak!

Email Address Data Annotation in C#

Validations are like gatekeepers – they ensure the correctness of user inputs to build reliable applications. Email addresses, being common entities in almost every application, are often a nightmare to validate correctly due to their complex nature comprised of local parts, @ symbol, domain names, and dot extensions.

But fret not, .NET has made this task easier for us with the built-in ’email address data annotation C#’. It’s time to pop the hood and investigate the mechanics of this significant feature.

When it comes to validating the patterns, regex is one of the first things that pops into our heads, right? But sometimes, the complexity of regex can feel like untangling a ball of string.

Email data annotation attribute insulates you from this unraveled complexity. After all, why take the long road when you have a short one?

Perhaps, you might be asking, “What’s the beef with this feature? Why should I use it?” The benefits are multi-fold: it ensures your database integrity, offers an enhanced user experience by providing immediate feedback, and protects your application from bad data and potential security exploits.

Advanced Email Address Data Annotation C#

Let’s dig deeper structurally. Below is a typical sign-up form model.

public class SignUp
{
    // Validates the email address
    [EmailAddress(ErrorMessage = "Invalid Email Address")]
    public string Email { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

Yes, that’s it! The annotation [EmailAddress] keeps a tight check on user input. It ensures that the string entered in Email is in a correct pattern, i.e., username@domain.extension.

It automatically generates a regex validation routine, leaving no chances for improperly formatted email addresses. If the input deviates from the requisite format, the user will get an ErrorMessage.

How about another example, where users have an optional second email address? You would want to validate it only when provided, not when left empty.

public class SignUp
{
    // Validates the primary email address
    [EmailAddress(ErrorMessage = "Invalid primary email address")]
    public string PrimaryEmail { get; set; }

    // Validates the secondary email address only if provided
    [EmailAddress(ErrorMessage = "Invalid secondary email address", SkipWhenEmpty = true)]
    public string SecondaryEmail { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

In the above code, the SkipWhenEmpty property ensures validation is bypassed if SecondaryEmail is left empty during form filling.

See, what did I tell you? It does sound like a magical tool in your coding arsenal. Don’t get fooled by its simplicity though, it’s powerful and efficient. The ’email address data annotation C#’ can be your silent coding ally, helping you maintain data hygiene in your beloved applications.

Exploring Data Annotation Attributes in C#

Did you know C# data annotation attributes are like the secret sauce that can add flavor to your data handling process? These attributes enable you to validate input data, control data layout, or adjust display details for smoother end-user interactions. Let’s further understand this with more examples and information.

Common Data Annotation Attributes in C#

To help you get started, here are some of the widely used data annotation attributes:

  • Required: The field under this attribute must hold a value. An empty input is not accepted.
  • StringLength: Controls the maximum length of a string.
  • Range: Enforces that the value of a property must fall within a specified range.
  • Compare: Compares two properties of a model.
  • DataType: Specifies the type of data (like Email, Phone Number, etc.) that the property holds.

Let’s see how these attributes function in reality.

public class EmployeeModel
{
    [Required(ErrorMessage = "Please enter name")]
    [StringLength(30)]
    [Display(Name = "Employee Name")]
    public string Name { get; set; }

    [Range(18, 65, ErrorMessage = "Age must be between 18 and 65")]
    public int Age { get; set; }

    [Required]
    [EmailAddress]
    [Display(Name = "Email Address")]
    public string Email { get; set; }

    [Required]
    [Compare("Password", ErrorMessage = "Password and Confirmation Password must match.")]
    public string ConfirmPassword { get; set; }

    [Required]
    public string Password { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

In the above snippet, we have used different annotation attributes for different properties. The Name property must be a string that is 30 characters long presented as ‘Employee Name’, the Age must be between 18 and 65, Email will be validated to ensure it holds a valid email format, Password and ConfirmPassword must match.

Combining MaxLength and Display Name Annotations

At times, you may find yourself in a situation where a single data annotation attribute is not enough. What do you do then? Combine them!

Let’s consider an example of a Student class, where we need to enforce a maximum length for the Name property and also have a customized display name for it. Here’s how we do it:

public class Student
{
    [MaxLength(30)][Display(Name = "Student's Full Name")]
    public string Name { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

In this code, the Name property is not going to accept more than 30 characters and will be displayed as ‘Student’s Full Name’ in the UI. This approach helps maintain data consistency and readability, making your code far easier to manage – how about that for coding convenience?

Why Stop at One? Multiple Attributes on a Single Property

C# Data Annotations are all about providing versatility and flexibility. Therefore, it’s not surprising that it allows you to apply multiple annotations onto a single property. Let’s say we have a Username field which requires uniqueness, has a max length limit, and needs to have a custom display name. We can accomplish this easily with data annotations:

public class User
{
    [Required]
    [MaxLength(20, ErrorMessage = "Username cannot exceed 20 characters")]
    [Display(Name = "User Handle")]
    [DataType(DataType.Text)]
    public string Username { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

With the help of multiple annotations, Username is now a required property with a length limit of 20 characters, a custom display name as ‘User Handle’, and it is expected to hold text data only.

C# Data Annotations Date Greater Than

Sometimes programming feels like a time travel adventure, especially when dealing with date validations. With ‘C# data annotations date greater than’, life becomes a lot easier. This feature plays a critical role in ensuring your date validations are properly ordered and managed.

Consider this example – you’re working on a project management app, where it’s crucial to ensure the task start date is always earlier than the end date. Let me show you how to magic this problem away with a nifty annotation.

Before we dive into the code, let’s understand the concept deeper. We don’t have a built-in attribute to compare two date properties, but don’t despair – C# got us covered! We can create our custom validation attribute for this purpose.

public class DateGreaterThanAttribute: ValidationAttribute
{
    private readonly string _comparisonProperty;

    // Set the name of the property to compare
    public DateGreaterThanAttribute(string comparisonProperty)
    {
        _comparisonProperty = comparisonProperty;
    }

    // Validate the date comparison
    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var currentValue = (DateTime)value;

        var comparisonValue = (DateTime)validationContext.ObjectType.GetProperty(_comparisonProperty)
                                                                    .GetValue(validationContext.ObjectInstance);

        if (currentValue < comparisonValue)
        {
            return new ValidationResult(ErrorMessage = "End date must be later than start date");
        }

        return ValidationResult.Success;
    }
}
Enter fullscreen mode Exit fullscreen mode

This custom attribute can be used to perform a date property comparison. It fetches the comparison property from the ValidationContext instance and performs a simple “greater than” check. If the end date is earlier than the start date, it throws a validation error.

Now let’s see this superhero in action:

public class Task
{
    public DateTime StartDate { get; set; }

    [DateGreaterThan("StartDate")]
    public DateTime EndDate { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

In the above snippet, the EndDate attribute verifies that it is indeed later than the StartDate.

C# Get Data Annotations from Property

Let’s further simplify our coding life with this next trick – fetching data annotations from properties. In the data annotation world, we often want to validate input based on the property’s annotation. Let’s break down how to ace this.

Suppose, we’re building a dynamic form where properties hold the critical validation information. These annotations can tell us required field information, min and max lengths, or any custom validation rules.

Here’s a chunk of code to demonstrate it:

public class DynamicForm
{
    [Required, MaxLength(50)]
    public string FirstName { get; set; }

    [Required, EmailAddress]
    public string Email { get; set; }
}

public void FetchAnnotations()
{
    var form = new DynamicForm();

    var type = form.GetType();

    foreach (var property in type.GetProperties())
    {
        var requiredAttr = property.GetCustomAttributes(typeof(RequiredAttribute), false);
        var emailAttr = property.GetCustomAttributes(typeof(EmailAddressAttribute), false);

        Console.WriteLine($"Property: {property.Name}");
        Console.WriteLine($"Is required: {requiredAttr.Length != 0}");
        Console.WriteLine($"Is email: {emailAttr.Length != 0}");
    }
}
Enter fullscreen mode Exit fullscreen mode

Running the FetchAnnotations function will print out the property names along with whether they have the Required and EmailAddress data annotations.

Time is slipping away, and now you may think, “What if I don’t use data annotations in C#?”, well, you are missing out on an effective way to validate data at the model level, making your coding life easier, faster and more efficient.

Top comments (3)

Collapse
 
xaberue profile image
Xavier Abelaira Rueda

Hi!! Thanks for sharing, amazing article by the way. I want to raise some questions:

  • Would you use data annotations in domain models or just in DTOs?
  • If using ECCore, will this use these annotations to properly shape de model accordingly to the DB? If yes, do we have more advantages doing this than using thd Fluent syntax in the DbContext?
  • Lastly, what's your opinion about FluentValidations?

Many thanks in advance and keep sharing these amazing articles! 👌

Collapse
 
karenpayneoregon profile image
Karen Payne

For FluentValidation check out my article which at the bottom has source code for Razor Pages which also applies to ASP.NET Core and used EF Core.

Collapse
 
karenpayneoregon profile image
Karen Payne

Well written and informative for new developers.