Custom Validation Attributes
Create custom validation attributes in ASP.NET Core
1. Introduction
It describes the why and how to create custom validation attributes. For details refer to the official documentation of Model Validation in ASP.NET Core MVC and Razor Pages.
2. Why do we need them?
We need custom validation attributes for scenarios that the built-in validation attributes don't handle. Custom validation attributes are a powerful way to enforce the rules in our ASP.NET Web APIs.
A few benefits of using custom validation attributes:
They help in improving the security of the web API.
They make sure that the data that is submitted to the web API is valid.
They make your code reusable - as the validation logic is written once and then can be used any number of times.
3. Naming them
The naming of custom validation attributes is an important aspect because it helps to communicate the purpose of the attribute to other developers without, them needing to dig into its logic.
Consider, we have to create a custom validation attribute that checks if the value is greater than 0. The possible names of the attributes are:
GreaterThanZeroValidationAttribute
PositiveIntegerValidationAttribute
NaturalNumberValidationAttribute
These names are descriptive that accurately reflect the purpose of the attribute. They are also short and do not contain any abbreviations or acronyms. I will choose GreaterThanZeroValidationAttribute
as the name effortlessly conveys its purpose to the reader.
4. How to create one?
Create a class GreaterThanZeroValidationAttribute
that inherits from ValidationAttributes
and override its IsValid
method.
The IsValid
method accepts an object named value
, which is the input to be validated. An overload also accepts a ValidationContext
object, which provides additional information, such as the model instance created by model binding.
[AttributeUsage(AttributeTarget.Property | AttributeTarget.Parameter)]
public class GreaterThanZeroValidationAttribute : ValidationAttribute
{
protected override ValidationResult? IsValid(Object? value, ValidationContext validationContext)
{
if (value is Int32 id && id > 1)
return ValidationResult.Success;
var errorMessage = String.Format("{0} must be greater than 0.", validationContext.MemberName!);
var result = new ValidationResult(errorMessage);
return result;
}
}
AttributeUsage
controls how the custom validation attribute class is used. For details visit AttributeUsageAttribute Class.
AttributeTarget.Property | AttributeTarget.Parameter
states what the class can target - properties & parameters, in this case. If [GreaterThanZeroValidation]
is used on anything else, it will produce a compilation error. For details visit AttributeTarget Enum.
5. Usage
5.1 When the target is a parameter
OrderController.cs
[ApiController]
[Route("api/[controller]")]
public class OrderController : ControllerBase
{
[HttpGet("{id}")]
public async Task<IActionResult> GetByIdAsync([GreaterThanZeroValidation] Int32 id)
{
//fetch the order using id, asynchronously.
}
}
5.2 When the target is a property of a class
OrderViewModel.cs
public class OrderViewModel
{
[GreaterThanZeroIntegerValidation]
public Int32 Id { get; set; }
public Dictionary<Int32, Int32> ProductQuantityMap { get; set; } = null!;
}
OrderController.cs
[HttpPost]
public async Task<IActionResult> CreateAsync(OrderViewModel viewModel)
{
//Do something with the viewModel.
}