liveBook · Manning

IValidatableObject

As explained in Building Web APIs with ASP.NET Core

IValidatableObject is a .NET interface that lets an object define validation logic involving its own values and relationships.

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

How Building Web APIs with ASP.NET Core covers it

How deep it goes
Walks through implementing Validate on a generic request DTO and reusing a sort-column validator.
Examples
Uses a board-game sort-column check and a DomainDTO rule involving Id or Name.
What it assumes
Assumes familiarity with C# DTO properties and validation attributes while introducing the interface as an alternative for class-level rules.
What you can do after
Build it from scratch by implementing Validate on a DTO and checking its validation outcome through an API action.
How it connects
Connects class-level validation to data annotation attributes, model binding, ModelState, and [ApiController] automatic validation.

Also explained in

Compare how 2 books explain IValidatableObject →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Building Web APIs with ASP.NET Core. The section links point to the parts of the book it draws on.