IValidatableObject lets a model validate relationships between its own property values when individual DataAnnotations attributes are not enough. Implement Validate and return ValidationResult objects describing any invalid combination. section 7.10.2
Listing 7.11 Implementing IValidatableObject
using System.ComponentModel.DataAnnotations; public record CreateUserModel : IValidatableObject #1 { [EmailAddress] #2 public string Email { get; set; } [Phone] #2 public string PhoneNumber { get; set; } public IEnumerable<ValidationResult> Validate( #3 ValidationContext validationContext) #3 { if(string.IsNullOrEmpty(Email) #4 && string.IsNullOrEmpty(PhoneNumber)) #4 { yield return new ValidationResult( #5 "You must provide an Email or a PhoneNumber", #5 New[] { nameof(Email), nameof(PhoneNumber) }); #5 } } } #1 Implements the IValidatableObject interface #2 The DataAnnotation attributes continue to validate basic format requirements. #3 Validate is the only function to implement in IValidatableObject. #4 Checks whether the object is valid . . . #5 . . . and if not, returns a result describing the error
Shows a CreateUserModel that combines Email and PhoneNumber attributes with a Validate method requiring at least one contact value. section 7.10.2
Use it with these practical boundaries:
- Keep isolated property checks in DataAnnotations, such as email and phone formats; use IValidatableObject when validity depends on multiple properties. section 7.10.2
- Return a ValidationResult with the error message and related property names, such as Email and PhoneNumber. section 7.10.2
- Remember that Validate runs only after all DataAnnotations conditions pass and does not provide easy access to application services. section 7.10.2
- Handle validation outcomes explicitly: Razor Pages runs validation after model binding, but the page handler still executes unless the application checks the result. section 16.3.1

