validation-patterns

Comprehensive validation patterns for ASP.NET Core applications. Covers FluentValidation integration, DataAnnotations, IValidatableObject, IValidateOptions<T>, MediatR pipeline behavior, and client-side validation. Use when implementing validation in ASP.NET Core applications, setting up FluentValid

By wshaddix · 526 installs

npx skills add wshaddix/dotnet-skills --skill validation-patterns

Source repository · Upstream listing

Validation Patterns in ASP.NET Core Rationale Validation is critical for both security and user experience. Poor validation leads to invalid data, security vulnerabilities, and confusing error messages. These patterns provide a comprehensive approach to validation at multiple layers. Validation Strategy Layer Purpose Technology Client Side Immediate feedback, reduce server load jQuery Validation, HTML5 Model Binding Data type/format validation Model Binders Application Business rule validation FluentValidation, DataAnnotations Configuration Startup validation IValidateOptions<T Database Constraint enforcement EF Core Configurations Validation Approach Decision Tree Choose the validation approach based on complexity: 1. DataAnnotations (default) declarative [Required] , [Range] , [StringLength] , [RegularExpression] attributes. Best for simple property level constraints. 2. IValidatableObject implement Validate() for cross property rules. Best for date range comparisons, conditional required fields. 3. Custom ValidationAttribute subclass ValidationAttribute for reusable property level rules. 4. IValidateOptions<T validate configuration/options classes at startup with access to DI services. 5. FluentValidation third party library for complex, testable validation with fluent API. Best for async validators, database dependent rules. Pattern 1: DataAnnotations The System.ComponentModel.DataAnnotations namespace provides declarative validation through attributes. Attribute Reference Attribute Purpose Example [Required] Non null, non empty [Required] [StringLength] Min/max length [StringLength(200, MinimumLength = 1)] [Range] Numeric/date range [Range(1, 100)] [RegularExpression] Pattern match [RegularExpression(@"^\d{5}$")] [EmailAddress] Email format [EmailAddress] [Phone] Phone format [Phone] [Url] URL format [Url] [CreditCard] Luhn check [CreditCard] [Compare] Property equality [Compare(nameof(Password))] [MaxLength] / [MinLength] Collection/string length [MaxLength(50)] [AllowedValues] (.NET 8+) Value allowlist [AllowedValues("Draft", "Published")] [DeniedValues] (.NET 8+) Value denylist [DeniedValues("Admin", "Root")] [Length] (.NET 8+) Min and max in one [Length(1, 200)] [Base64String] (.NET 8+) Base64 format [Base64String] Pattern 2: Custom ValidationAttribute Create reusable validation attributes for domain specific rules. Property Level Class Level Pattern 3: IValidatableObject Implement IValidatableObject for cross property validation within the model: When to use IValidatableObject vs custom attribute: Use IValidatableObject when validation logic is specific to one model. Use custom ValidationAttribute when the same rule applies across multiple models. Pattern 4: IValidateOptions<T Validate configuration/options classes at startup with access to DI services: Registration Pattern 5: FluentValidation Setup NuGet Packages Configuration Basic Validator Conditional Validation Collection Validation Pattern 6: MediatR Validation Pipeline Behavior Registration Pattern 7: Manual Validation Run DataAnnotations validation programmatically: Critical: Without validateAllProperties: true , Validator.TryValidateObject only checks [Required] attributes. Pattern 8: Validating File Uploads Anti Patterns Duplicate Validation Silent Validation Failures Trusting Client Side Validation Agent Gotchas 1. Always pass validateAllProperties: true to Validator.TryValidateObject . 2. Options classes must use { get; set; } not { get; init; } configuration binder needs to mutate properties. 3. IValidatableObject.Validate() runs only after all attribute validations pass do not rely on it for primary validation. 4. Do not inject services into ValidationAttribute via constructor use validationContext.GetService<T () inside IsValid() . 5. Register IValidateOptions<T as singleton the options validation infrastructure resolves validators as singletons. 6. Do not forget ValidateOnStart() without it, options validation only runs on first access. References [FluentValidation](https://docs.fluentvalidation.net/) [Model Validation in ASP.NET Core](https://learn.microsoft.com/en us/aspnet/core/mvc/models/validation) [Data Annotations](https://learn.microsoft.com/en us/dotnet/api/system.componentmodel.dataannotations) [IValidateOptions](https://learn.microsoft.com/en us/dotnet/core/extensions/options options validation) [jQuery Validation](https://jqueryvalidation.org/)