| Package | Downloads | License |
|---|---|---|
You can find the source code and contribute on GitHub
FlowValidate is a lightweight, fluent-style validation library for .NET.
It provides an intuitive API for validating models, making it easy to add and enforce rules while reducing boilerplate code.
- Property Validation: Validate standard properties, nested objects, and collections.
- Nested & Collection Support: Automatically validates complex types and lists.
- Custom Rules: Use
Should,Must,IsNotEmpty,IsEqualor define your own logic. - Multi-error per Rule: Single property rules can produce multiple error messages.
- Reusable & Property-specific Validators: Create modular validators like
UserNameValidatorand apply them to properties. - Async / Task-based Validation: Rules can run asynchronously (
MustAsync/ShouldAsync) with a synchronous validation fallback bridge. - DI Support: Easy integration with dependency injection.
- Clear Error Messages: Provides detailed validation feedback.
- Detailed Error Messages: Provides rich validation feedback with property name, attempted value, and optional error code.
- Lightweight & Fast: Optimized for high performance.
- Middleware Ready: Can validate models automatically on each request.
You can install FlowValidate via NuGet Package Manager
dotnet add package FlowValidatevar builder = WebApplication.CreateBuilder(args);
builder.Services.FlowValidationService(AssemblyReference.Assembly);
var app = builder.Build();
app.FlowValidationApp();
app.Run();public class UserNameValidator : BaseValidator<string>
{
public UserNameValidator()
{
RuleFor(name => name).IsNotEmpty().WithMessage("Name cannot be empty.")
.Length(3, 100).WithMessage("Name must be at least 3 characters.");
}
}public class UserDetailsValidator : BaseValidator<UserDetails>
{
public UserDetailsValidator()
{
RuleFor(x => x.Email).IsEmail().WithMessage("Email is invalid.");
RuleFor(x => x.Phone).MatchesRegex(@"^\d{10}$").WithMessage("Phone must be 10 digits.");
}
}public class UserBasketValidator : BaseValidator<UserBasket>
{
public UserBasketValidator()
{
RuleFor(x => x.Name).IsNotEmpty();
RuleFor(x => x.Count).IsGreaterThan(0);
}
}public class UserValidator : BaseValidator<User>
{
public UserValidator()
{
// Registry rule
ValidateRegistryRules(u => u.Name, new UserNameValidator());
// Nested validator
ValidateNested(u => u.Details, new UserDetailsValidator());
// Collection validator
ValidateCollection(u => u.Baskets, new UserBasketValidator(), item => item);
// Custom validation with Should
RuleFor(u => u.Nickname)
.Should((nickname, addError) =>
{
if (!string.IsNullOrEmpty(nickname))
{
if (nickname.Length < 3)
addError("Nickname must be at least 3 characters long.");
if (nickname.Contains(" "))
addError("Nickname cannot contain spaces.");
}
});
}
}FlowValidate fully supports asynchronous validation rules for operations that require external or asynchronous calls (e.g., database queries or external API requests). You can use MustAsync and ShouldAsync inside your validators.
public class UserValidator : BaseValidator<User>
{
private readonly IUserRepository _userRepository;
public UserValidator(IUserRepository userRepository)
{
_userRepository = userRepository;
// Using MustAsync for custom async boolean conditions
RuleFor(u => u.Email)
.MustAsync(async email => !await _userRepository.ExistsAsync(email))
.WithMessage("This email address is already in use.");
// Using ShouldAsync with a multi-error delegate callback
RuleFor(u => u.Username)
.ShouldAsync(async (username, addError) =>
{
var isBlacklisted = await _userRepository.IsBlacklistedAsync(username);
if (isBlacklisted)
{
addError("Username is blacklisted.");
}
});
// Using ShouldAsync with an action exception boundary
RuleFor(u => u.Bio)
.ShouldAsync(async bio =>
{
await _userRepository.ValidateBioFormatAsync(bio); // Throws if invalid
}, "Bio format is invalid.");
}
}var validator = new UserValidator(userRepository);
// 1. Asynchronous execution (Recommended when using async rules)
var resultAsync = await validator.ValidateAsync(user);
// 2. Synchronous execution bridge (Executes async rules synchronously under the hood)
var resultSync = validator.Validate(user);var user = new User
{
Name = "Jo",
Age = 25,
Details = new UserDetails { Email = "invalid-email", Phone = "12345" },
Baskets = new List<UserBasket>
{
new UserBasket { Name = "", Count = 0 },
new UserBasket { Name = "Apple", Count = 3 }
}
};
var validator = new UserValidator();
var result = validator.Validate(user);For more examples and unit tests, check the FlowValidate.Test project in the repository.