Vali-Validation
2.0.2
dotnet add package Vali-Validation --version 2.0.2
NuGet\Install-Package Vali-Validation -Version 2.0.2
<PackageReference Include="Vali-Validation" Version="2.0.2" />
<PackageVersion Include="Vali-Validation" Version="2.0.2" />
<PackageReference Include="Vali-Validation" />
paket add Vali-Validation --version 2.0.2
#r "nuget: Vali-Validation, 2.0.2"
#:package Vali-Validation@2.0.2
#addin nuget:?package=Vali-Validation&version=2.0.2
#tool nuget:?package=Vali-Validation&version=2.0.2
Vali-Validation
Vali-Validation is a lightweight, zero-dependency fluent validation library for .NET 7, 8, and 9. It provides a clean, expressive API for defining validation rules on your models, with full support for async validation, conditional rules, nested object validation, collection validation, cascade mode, error codes, custom rules, and seamless dependency injection — all without requiring any external dependencies beyond Microsoft.Extensions.DependencyInjection.Abstractions.
Installation
dotnet add package Vali-Validation
Quick Start
Define a validator by subclassing AbstractValidator<T> and configuring rules in the constructor:
using Vali_Validation.Core.Validators;
public class CreateUserDto
{
public string? Name { get; set; }
public string? Email { get; set; }
public string? Password { get; set; }
public int Age { get; set; }
}
public class CreateUserValidator : AbstractValidator<CreateUserDto>
{
public CreateUserValidator()
{
RuleFor(x => x.Name)
.NotEmpty()
.MinimumLength(2)
.MaximumLength(100);
RuleFor(x => x.Email)
.NotEmpty()
.Email();
RuleFor(x => x.Password)
.NotEmpty()
.MinimumLength(8)
.HasUppercase()
.HasLowercase()
.HasDigit()
.HasSpecialChar();
RuleFor(x => x.Age)
.GreaterThanOrEqualTo(18)
.LessThan(120);
}
}
Use the validator:
var validator = new CreateUserValidator();
var result = validator.Validate(dto);
if (!result.IsValid)
{
foreach (var error in result.ToFlatList())
Console.WriteLine(error);
}
// Async
var result = await validator.ValidateAsync(dto, cancellationToken);
// Throw on failure
validator.ValidateAndThrow(dto);
await validator.ValidateAndThrowAsync(dto, cancellationToken);
Available Rules
| Rule | Description |
|---|---|
NotEmpty() |
Value must not be null or whitespace |
NotNull() |
Value must not be null |
Null() |
Value must be null |
Empty() |
Value must be null or empty string |
Must(predicate) |
Custom sync predicate |
MustAsync(predicate) |
Custom async predicate |
MustAsync(predicate, ct) |
Custom async predicate with CancellationToken |
Custom(action) |
Custom validation action with full context |
MinimumLength(n) |
String length >= n |
MaximumLength(n) |
String length ⇐ n |
LengthBetween(min, max) |
String length between min and max |
Matches(pattern) |
Must match regex pattern |
Email() |
Must be a valid email address |
Url() |
Must be a valid HTTP/HTTPS URL |
PhoneNumber() |
Must be a valid E.164 phone number |
IPv4() |
Must be a valid IPv4 address |
CreditCard() |
Must pass Luhn check |
Guid() |
Must be a valid GUID string |
NotEmptyGuid() |
Must be a non-empty GUID |
IsAlpha() |
Only alphabetic characters |
IsAlphanumeric() |
Only alphanumeric characters |
IsNumeric() |
Only numeric characters |
NoWhitespace() |
No whitespace characters |
EqualTo(value) |
Must equal the given value |
NotEqual(value) |
Must not equal the given value |
EqualToProperty(expr) |
Must equal another property |
GreaterThan(n) |
Must be greater than n |
LessThan(n) |
Must be less than n |
GreaterThanOrEqualTo(n) |
Must be >= n |
LessThanOrEqualTo(n) |
Must be ⇐ n |
Between(min, max) |
Inclusive range |
ExclusiveBetween(min, max) |
Exclusive range |
Positive() |
Must be > 0 |
Negative() |
Must be < 0 |
NotZero() |
Must not be 0 |
Odd() |
Must be an odd integer |
Even() |
Must be an even integer |
MultipleOf(factor) |
Must be a multiple of factor |
MaxDecimalPlaces(n) |
At most n decimal places |
In(values) |
Must be in the allowed list |
NotIn(values) |
Must not be in the disallowed list |
StartsWith(prefix) |
String must start with prefix |
EndsWith(suffix) |
String must end with suffix |
MustContain(substring) |
String must contain substring |
NotContains(substring) |
String must not contain substring |
FutureDate() |
DateTime must be in the future |
PastDate() |
DateTime must be in the past |
Today() |
DateTime must be today |
IsEnum<TEnum>() |
Must be a valid enum value |
HasCount(n) |
Collection must have exactly n items |
MinCount(n) |
Collection must have at least n items |
MaxCount(n) |
Collection must have at most n items |
NotEmptyCollection() |
Collection must not be empty |
Unique() |
Collection must have no duplicates |
AllSatisfy(predicate) |
All collection items must satisfy predicate |
AnySatisfy(predicate) |
At least one item must satisfy predicate |
HasUppercase() |
String must contain an uppercase letter |
HasLowercase() |
String must contain a lowercase letter |
HasDigit() |
String must contain a digit |
HasSpecialChar() |
String must contain a special character |
Lowercase() |
String must be all lowercase |
Uppercase() |
String must be all uppercase |
MinWords(n) |
String must have at least n words |
MaxWords(n) |
String must have at most n words |
Modifiers
| Modifier | Description |
|---|---|
WithMessage(msg) |
Override the error message; supports {PropertyName} and {PropertyValue} |
WithErrorCode(code) |
Attach an error code to the rule |
OverridePropertyName(name) |
Use a custom key in error dictionaries |
StopOnFirstFailure() |
Stop evaluating rules for this property after first failure |
When(condition) |
Only run preceding rules when condition is true |
Unless(condition) |
Only run preceding rules when condition is false |
WhenAsync(condition) |
Async version of When |
UnlessAsync(condition) |
Async version of Unless |
Message Templates
Error messages support {PropertyName} and {PropertyValue} placeholders:
RuleFor(x => x.Age)
.GreaterThan(0)
.WithMessage("'{PropertyName}' value '{PropertyValue}' must be positive.");
CascadeMode
Stop validation after the first property failure across all properties:
public class MyValidator : AbstractValidator<MyDto>
{
protected override CascadeMode GlobalCascadeMode => CascadeMode.StopOnFirstFailure;
public MyValidator()
{
RuleFor(x => x.Name).NotEmpty();
RuleFor(x => x.Email).Email(); // Skipped if Name already fails
}
}
Nested Validators
RuleFor(x => x.Address).SetValidator(new AddressValidator());
Collection Validation
RuleForEach(x => x.Tags).NotEmpty().MinimumLength(2);
DI Registration
// Register all validators from an assembly
services.AddValidationsFromAssembly(typeof(CreateUserValidator).Assembly);
// Or register individually
services.AddScoped<IValidator<CreateUserDto>, CreateUserValidator>();
Links
Donations
If Vali-Validation is useful to you, consider supporting its development:
- Latin America — MercadoPago
- International — PayPal
License
Contributions
Issues and pull requests are welcome on GitHub.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net7.0
-
net8.0
-
net9.0
NuGet packages (3)
Showing the top 3 NuGet packages that depend on Vali-Validation:
| Package | Downloads |
|---|---|
|
Vali-Validation.MediatR
MediatR integration for Vali-Validation. Adds a ValidationBehavior<TRequest, TResponse> pipeline behavior that automatically validates IRequest objects using Vali-Validation before they reach their handler. Throws ValidationException on failure. Use Vali-Mediator.Validation instead if you use Vali-Mediator — it provides richer integration with Result<T> support (no exceptions needed). |
|
|
Vali-Validation.ValiMediator
Vali-Mediator integration for Vali-Validation. Adds a ValidationBehavior<TRequest, TResponse> that validates IRequest objects before they reach their handler. When TResponse is Result<T>, validation failures are returned as Result.Fail(errors, ErrorType.Validation) — no exceptions needed. For other response types, throws ValidationException. Package name: Vali-Validation.ValiMediator. Requires Vali-Mediator. |
|
|
Vali-Validation.AspNetCore
ASP.NET Core integration for Vali-Validation. Provides: - ValiValidationMiddleware: catches ValidationException and returns HTTP 400 problem+json. - ValiValidationFilter<T>: Minimal API endpoint filter for automatic request validation. - ValiValidateAttribute: MVC action filter for automatic controller action validation. - UseValiValidationExceptionHandler() and WithValiValidation<T>() extension methods. |
GitHub repositories
This package is not used by any popular GitHub repositories.
v2.0.2 — Bug fix for async validation messages:
- Fixed MustAsync() to properly support .WithMessage() for custom error messages on async rules.
- Created MessageWrapper to allow message updates after async rule registration.
- Async validation messages now correctly override default messages.
v2.0.0 — Major improvements and new features:
Bug fixes:
- ValidateAsync now exposed on IValidator<T> interface (was missing).
- Validate() no longer deadlocks in ASP.NET Core: sync and async rules run in separate lists.
- LessThan() had wrong error message ("greater than") — fixed.
- Positive() no longer accepts zero (semantics fix).
- Expression body crash fixed for non-MemberExpression selectors (e.g. x => x.Name.ToLower()).
- MustAsync no longer registers an empty sync delegate unnecessarily.
- isValidAlpha renamed to IsValidAlpha (naming convention fix).
Design improvements:
- ValidationResult.Errors changed from Dictionary<string, List<string?>> to List<string> (errors are never null).
- Constants.cs removed (Zero/One literals added no value).
- AddValidationsFromAssembly now accepts optional ServiceLifetime parameter (default Transient).
- New ValidationException typed exception in Core/Exceptions/.
- ValidateAndThrow() and ValidateAndThrowAsync() added to AbstractValidator.
New features:
- When(Func<T, bool>) / Unless(Func<T, bool>) — conditional rule execution.
- StopOnFirstFailure() — stop evaluating rules for a property after first failure.
- SetValidator(AbstractValidator<TProperty>) — delegate validation to nested validators.
- RuleForEach(x => x.Collection) — validate each element with indexed error keys (Items[0]).
- OverridePropertyName(string) — control the error key in ValidationResult.Errors.