# EasyValidate - .NET Validation Library ## Overview EasyValidate is a modern, type-safe .NET validation library using source generators, Roslyn analyzers, and code fixers. It provides compile-time code generation for efficient runtime validation. ## Installation ```bash dotnet add package EasyValidate ``` ## Quick Start ```csharp using EasyValidate.Abstractions; using EasyValidate.Attributes; // Class MUST be partial and implement IGenerate public partial class User : IGenerate { [NotNull] [NotEmpty] public string? Name { get; set; } [NotNull] [EmailAddress] public string? Email { get; set; } [Range(18, 120)] public int Age { get; set; } } // Usage var user = new User { Name = "John", Email = "john@example.com", Age = 25 }; var result = user.Validate(); if (result.IsValid()) { /* valid */ } ``` ## Key Concepts ### 1. IGenerate Interface All classes with validation attributes MUST: - Be declared as `partial` - Implement `IGenerate` interface ### 2. Validation Chains Group related validations using the `Chain` property: ```csharp [NotNull(Chain = "shipping")] [FutureDate(Chain = "shipping")] public DateTime? ShippingDate { get; set; } ``` ### 3. Conditional Validation Use `ConditionalMethod` to conditionally run validation: ```csharp [NotNull(ConditionalMethod = nameof(ShouldValidate))] public string? OptionalField { get; set; } private bool ShouldValidate(IChainResult result) => condition; ``` ### 4. Async Validation Implement `IAsyncValidationAttribute` for database/API calls: ```csharp public async Task ValidateAsync(string propertyName, string value) { var exists = await _repository.ExistsAsync(value); return exists ? AttributeResult.Fail("Already exists") : AttributeResult.Success(); } ``` ### 5. Parameter Validation Apply attributes to method parameters: ```csharp public void Process([NotNull] string? value, [Range(1, 100)] int count) { } ``` ## Available Attributes ### String Attributes - `NotEmpty` - Not null, empty, or whitespace - `EmailAddress` - Valid email format - `Url` - Valid URL - `Phone` - Valid phone number - `CreditCard` - Valid credit card (Luhn) - `Alpha` - Only letters - `AlphaNumeric` - Only letters and numbers - `Numeric` - Parseable as number - `Matches(pattern)` - Regex match - `StartsWith(prefix)`, `EndsWith(suffix)`, `Contains(substring)`, `NotContains(substring)` - `OneOf(...values)`, `NotOneOf(...values)` - `Uppercase`, `Lowercase`, `FirstLetterUpper` - `NoWhitespace` - `Guid`, `Hex`, `Color`, `IpAddress`, `MacAddress`, `ISBN`, `Ascii` - `BaseEncoding(type)`, `FileExtension(...extensions)`, `ValidEnum(typeof(T))` ### Numeric Attributes - `Range(min, max)` - Value in range - `Positive`, `Negative`, `NonZero` - `GreaterThan(value)`, `GreaterThanOrEqualTo(value)` - `LessThan(value)`, `LessThanOrEqualTo(value)` - `DivisibleBy(divisor)`, `MultipleOf(value)` - `EvenNumber`, `OddNumber`, `Prime`, `Fibonacci` - `PowerOf(base)` - `MinDigits(count)`, `MaxDigits(count)` ### Date Attributes - `PastDate`, `FutureDate`, `Today`, `NotTodayDate` - `NotInPast`, `NotInFuture` - `DateRange(min, max)`, `TimeRange(start, end)` - `MinAge(years)`, `MaxAge(years)`, `AgeRange(min, max)` - `DayOfWeek(...days)`, `Day(...days)`, `Month(...months)`, `Year(...years)` - `Quarter(...quarters)` - `LeapYear`, `NotLeapYear` - `UTC`, `NotUTC` ### Collection Attributes - `HasElements` - At least one element - `MinLength(count)`, `MaxLength(count)`, `Length(exactCount)` - `UniqueElements`, `NoNullElements` - `ContainsElement(value)`, `NotContainElement(value)` - `Single(value)`, `SingleOrNone(value)` ### General Attributes - `NotNull` - Value not null - `Optional` - Null is allowed - `NotDefault` - Not default value - `EqualTo(value)`, `NotEqualTo(value)` ## Common Properties (All Attributes) - `ErrorCode` - Custom error identifier - `Chain` - Validation chain name - `ConditionalMethod` - Method name for conditional execution ## Analyzer Error Codes - EASY001-003: Attribute inheritance/usage issues - EASY004-006: Attribute parameter issues - EASY007-010: Chain validation issues - EASY011-015: Conditional method issues - EASY016-019: Setup and design issues ## Best Practices 1. Always use `partial` classes with `IGenerate` 2. Order: `NotNull` → `NotEmpty` → specific validations 3. Use `nameof()` for `ConditionalMethod` 4. Set meaningful `ErrorCode` values 5. Implement both sync and async methods in `IAsyncValidationAttribute` ## Links - Documentation: https://easy-validate.netlify.app - Repository: https://github.com/mu-dawood/EasyValidate - NuGet: https://www.nuget.org/packages/EasyValidate