Build Custom Validation Libraries
Create your own validation attribute libraries that seamlessly integrate with EasyValidate. Reference EasyValidate.Abstractions to build domain-specific, reusable validation rules.
Quick Start
Get started with creating your own validation attribute library in 3 simple steps
1
Reference Abstractions
Add the EasyValidate.Abstractions NuGet package to your library project
2
Implement Interface
Create attributes implementing IValidationAttribute<T>
3
Return Results
Use AttributeResult to return success or failure
Core Interfaces
Understanding the interfaces you need to implement for your custom attributes
IValidationAttribute<TInput>
The primary interface for synchronous validation without value transformation. Use this for most validation scenarios.
Required Members
ErrorCode- Unique identifier for this validation errorConditionalMethod- Method name for conditional execution (optional)Chain- Group name for validation chainingValidate()- Core validation logic returning AttributeResult
Use When
- Simple pass/fail validation without modifying values
- Format validation (email, phone, URL)
- Range checking and constraints
- Pattern matching and regex validation
Built-in Base Classes
EasyValidate provides base classes you can extend for common validation scenarios
StringValidationAttributeBase
Base class for string validation attributes. Requires referencing EasyValidate.Attributes package in addition to EasyValidate.Abstractions.
Supported Types: string
NumericValidationAttributeBase
Base class for numeric validation. Requires referencing EasyValidate.Attributes package. Supports int, long, decimal, double, float, and their nullable variants.
Supported Types: int, long, decimal, double, float (+ nullable)
DateValidationAttributeBase
Base class for date/time validation. Requires referencing EasyValidate.Attributes package. Supports DateTime, DateTimeOffset, and DateOnly (.NET 6+).
Supported Types: DateTime, DateTimeOffset, DateOnly
CollectionValidationAttributeBase
Base class for collection validation. Requires referencing EasyValidate.Attributes package. Validates IEnumerable, arrays, lists, and other collections.
Supported Types: IEnumerable<T>, List<T>, T[], ICollection<T>
Complete Examples
Real-world examples of custom validation attribute libraries
Domain-Specific Validation Library
Create validation attributes specific to your business domain
AttributeResult API
Return validation results using the AttributeResult struct
Success Methods
Failure Methods
Advanced Features
Leverage advanced EasyValidate features in your custom attributes
ValidationContext Injection
Access the parent model instance for cross-property validation
Dependency Injection
Services are automatically injected via init properties
Conditional Validation
Support conditional execution based on other properties
Validation Chains
Group validations that should run together
Best Practices
Guidelines for building high-quality validation attribute libraries
Do: Use Descriptive Error Messages
Include the actual value and constraints in error messages using format placeholders: AttributeResult.Fail("Value {0} must be at least {1}", value, minValue)
Do: Handle Null Values Gracefully
Return Success for null/empty values and let NotNull/NotEmpty attributes handle those cases. This allows proper attribute composition.
Do: Use Meaningful Error Codes
Use unique, descriptive error codes like 'INVALID_EMAIL_FORMAT' or 'VALUE_OUT_OF_RANGE' for programmatic error handling.
Do: Make Attributes Configurable
Use public properties with default values to allow customization: public int MaxLength { get; set; } = 100;
Don't: Throw Exceptions in Validate Methods
Always return AttributeResult.Fail() instead of throwing exceptions. Exceptions break the validation chain and provide poor user experience.
Don't: Perform Heavy Computation in Sync Validation
Use IAsyncValidationAttribute for any I/O operations, database queries, or expensive computations to avoid blocking.
Don't: Hardcode Messages Without Placeholders
Avoid hardcoding specific values in messages. Use format placeholders so messages can include context: {0}, {1}, etc.
Don't: Depend on Validation Order
Don't assume attributes will execute in a specific order. Each attribute should be independent and self-contained.
Project Setup
Recommended project structure for your validation attribute library