ValidationAttribute
Here are a few advantages of using ValidationAttribute for custom annotations in a RESTful API:
Separation of Concerns: By using validation attributes, the validation logic can be separated from the business logic. This makes the code cleaner and easier to understand.
Reusability: Custom validation attributes can be used multiple times across different classes or properties. This prevents code duplication and promotes the DRY (Don't Repeat Yourself) principle.
Declarative Programming: Applying an attribute to a property or class is more declarative than imperative. It clearly specifies how the validation should be done without cluttering the business logic.
Integration with Model Binding: In ASP.NET Core, model binding automatically applies these validation attributes during the model binding process.
Automatic Error Messages: A friendly error message is automatically added to the ModelState.Errors collection. These error messages can also be customized as per your needs.
Enforcing Business Rules: Custom validation attributes can enforce business rules at the data level.
IsValid method: Allows us to override the IsValid method where we define our custom validation logic.
Below is an example that demonstrates the ValidationAttribute implementation against a more object-oriented style just for reference.
public class CreateBookDto
{
private string _title { get; set; }
public string Title
{
get => _title;
set
{
if (value == Author)
{
throw new InvalidOperationException("Title and Author should not be having the same value");
}
_title = value;
}
}
private string _author { get; set; }
public string Author
{
get => _author;
set
{
if (value == _title)
{
throw new InvalidOperationException("Title and Author should not be having the same value");
}
_author = value;
}
}
[IsbnShouldNotBeTitle(nameof(Title), ErrorMessage = "ISBN should not be same as Title")]
public string Isbn { get; set; }
public int Copies { get; set; }
}
public class IsbnShouldNotBeTitle : ValidationAttribute
{
private readonly string _targetProperty;
public IsbnShouldNotBeTitle(string targetProperty)
{
_targetProperty = targetProperty;
}
protected override ValidationResult IsValid(object? value, ValidationContext validationContext)
{
var targetProperty = validationContext.ObjectType.GetProperty(_targetProperty);
if (targetProperty is null)
{
return new ValidationResult($"Property {_targetProperty} not found");
}
if (value is null)
{
return new ValidationResult($"You need to pass in a value to validate");
}
var targetValue = targetProperty.GetValue(validationContext.ObjectInstance, null);
if (targetValue != null && value.ToString() == targetValue.ToString())
{
return new ValidationResult(ErrorMessage);
}
return ValidationResult.Success!;
}
}
ValidationAttribute shines when we want to keep a tidy house to assist the team in focusing on business logic while we clearly communicate the rules.
No files yet, migration hasn't completed yet!