Data Annotation Validation in .NET Core

Introduction

In this article, we will discuss how to create a custom validation attribute in .Net. First of all, what is the need for this, as .net already provides many built-in validation attributes?

Sometimes when we are working with real-time applications, there are some requirements to validate the input for which built-in attributes did not work, then we can create custom validation attributes.

A custom validation attribute lets you create metadata that you can use in the data model to validate data fields.

Logic will reside in one place, and attributes can be reused.

Readability and Maintainability of code

Let's create one Custom data annotation attribute that will allow the emailAddress from a specified domain e.g.: microsoft.com.

Create the class DomainValidationAttribute, which will inherit the ValidationAttribute Class.

Now override the IsValid method.

public class DomainValidationAttribute : ValidationAttribute
{
    public override bool IsValid(object value)
    {
        if (value is string email)
        {
            // Validation logic
            // Return true/false based on validation logic
        }
        return false;
    }        
}

Override the FormatErrorMessage, to provide a meaningful error message.

public override string FormatErrorMessage(string name)
{
    return $"{name} only allowed {_domain} domain.";
}

Add the attribute to the Model class property.

public class Employee
{
    [Required]
    [EmailAddress]
    [DomainValidation("microsoft.com")]
    public string Email { get; set; }
}

Add the parameterized constructor to accept the dynamic domain name and the final version of the DomainValidationAttribute class.

public class DomainValidationAttribute : ValidationAttribute
{
    private readonly string _domain;

    public DomainValidationAttribute(string domain)
    {
        _domain = domain;
    }

    public override bool IsValid(object value)
    {
        if (value is string email)
        {
            var splitEmail = email.Split("@");
            return splitEmail.Length == 2 && splitEmail[1].Contains(_domain, StringComparison.OrdinalIgnoreCase);
        }
        return false;
    }

    public override string FormatErrorMessage(string name)
    {
        return $"{name} only allowed {_domain} domain.";
    }
}

Now will use this model in our controller action method, as shown below.

    [ApiController]
    [Route("[controller]")]
    public class EmployeeController : ControllerBase
    {
        [HttpPost]
        public IActionResult Create([FromBody]Employee employee)
        {   // Create Employee in DB
            return Ok();
        }
     }

Now we will run the application and try to hit the action method using swagger.

Valid Domain Request: microsoft.com

Valid Domain Request

Invalid Domain Request:  example.com

Invalid Domain Request

In ASP.NET, MVC or ASP.NET Web API provides mechanisms to perform model validation using attributes, annotations, or validation libraries. This helps the developer define validation rules for the data models and automatically trigger validation during the data binding process within the controller.

But if we want to use data annotation validation in a console application or other than an action method, then we need to do this manually using ValidationContext and Validator.TryValidateObject method as shown below.

public bool CreateEmployee()
{
    var emp = new Employee()
    {
        Email = "[email protected]"
    };
    var validationContext = new ValidationContext(emp);
    var validationResults = new List<ValidationResult>();

    bool isValid = Validator.TryValidateObject(emp, validationContext, validationResults, true);

    if (!isValid)
    {
        foreach (var result in validationResults)
        {
            Console.WriteLine(result.ErrorMessage);
        }
        return false;
    }
    // Create Employee in DB
    return true;
}

Summary

In this article, we learned about how to create a custom data validation attribute in .Net Core. How the data validation we can call manually if we are working on some console or other project? 

Hope this article finds you well. Thanks for reading this.


Similar Articles