IValidatableObject lets a DTO validate itself as a whole. Use it when a rule depends on multiple values or on the type of object the DTO describes. It complements property-level validation attributes rather than replacing them. section 6.1.5
A board-game listing request accepts a sort-column name. To check that name against the properties of the DTO being listed, declare the request as RequestDTO<T> : IValidatableObject and implement Validate(ValidationContext). The method can inspect typeof(T) and validate SortColumn. Unlike an attribute argument, this approach can use the generic type parameter. section 6.1.5
Listing 6.6 RequestDTO.cs file (version 2)
using MyBGList.Attributes;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace MyBGList.DTO
{
public class RequestDTO<T> : IValidatableObject #1
{
[DefaultValue(0)]
public int PageIndex { get; set; } = 0;
[DefaultValue(10)]
[Range(1, 100)]
public int PageSize { get; set; } = 10;
[DefaultValue("Name")]
public string? SortColumn { get; set; } = "Name";
[SortOrderValidator]
[DefaultValue("ASC")]
public string? SortOrder { get; set; } = "ASC";
[DefaultValue(null)]
public string? FilterQuery { get; set; } = null;
public IEnumerable<ValidationResult> Validate( #2
ValidationContext validationContext)
{
var validator = new SortColumnValidatorAttribute(typeof(T));
var result = validator
.GetValidationResult(SortColumn, validationContext);
return (result != null)
? new [] { result }
: new ValidationResult[0];
}
}
}
The revised RequestDTO keeps property-level rules for page size and sort order while adding class-level validation for the sort column. section 6.1.5
Validate a relationship between fields
A DomainDTO rule can accept a request when Id is 3 or Name is "Wargames". If neither condition holds, validation emits "Id and/or Name values must match an allowed Domain." A POST action accepting DomainDTO can be used to check the HTTP response. section 6.3.3
ASP.NET Core model binding validates incoming request data and combines validation results in ModelState. An API can use [ApiController] automatic validation or inspect ModelState manually to customize the response. section 6.4

