FunctionalDdd.FluentValidation
3.0.0-alpha.3
See the version list below for details.
dotnet add package FunctionalDdd.FluentValidation --version 3.0.0-alpha.3
NuGet\Install-Package FunctionalDdd.FluentValidation -Version 3.0.0-alpha.3
<PackageReference Include="FunctionalDdd.FluentValidation" Version="3.0.0-alpha.3" />
<PackageVersion Include="FunctionalDdd.FluentValidation" Version="3.0.0-alpha.3" />
<PackageReference Include="FunctionalDdd.FluentValidation" />
paket add FunctionalDdd.FluentValidation --version 3.0.0-alpha.3
#r "nuget: FunctionalDdd.FluentValidation, 3.0.0-alpha.3"
#:package FunctionalDdd.FluentValidation@3.0.0-alpha.3
#addin nuget:?package=FunctionalDdd.FluentValidation&version=3.0.0-alpha.3&prerelease
#tool nuget:?package=FunctionalDdd.FluentValidation&version=3.0.0-alpha.3&prerelease
Fluent Validation Extension
This library seamlessly integrates FluentValidation with Railway Oriented Programming, converting FluentValidation errors into FunctionalDDD ValidationError objects.
Table of Contents
Installation
Install both packages via NuGet:
dotnet add package FunctionalDDD.FluentValidation
dotnet add package FluentValidation
Why Use This Extension
Without this extension, you would manually convert validation errors:
var validator = new UserValidator();
var validationResult = validator.Validate(user);
if (!validationResult.IsValid)
{
var errors = validationResult.Errors
.Select(e => Error.Validation(e.ErrorMessage, e.PropertyName));
return Result.Failure<User>(Error.Aggregate(errors));
}
return Result.Success(user);
With this extension, validation integrates seamlessly with ROP:
return Validator.ValidateToResult(user);
Quick Start
Inline Validator
The simplest approach using InlineValidator:
public partial class User : Aggregate<UserId>
{
public FirstName FirstName { get; }
public LastName LastName { get; }
public EmailAddress Email { get; }
public int Age { get; }
public static Result<User> TryCreate(
FirstName firstName,
LastName lastName,
EmailAddress email,
int age)
{
var user = new User(firstName, lastName, email, age);
return Validator.ValidateToResult(user);
}
private User(FirstName firstName, LastName lastName, EmailAddress email, int age)
: base(UserId.NewUnique())
{
FirstName = firstName;
LastName = lastName;
Email = email;
Age = age;
}
// Fluent Validation
private static readonly InlineValidator<User> Validator = new()
{
v => v.RuleFor(x => x.FirstName).NotNull(),
v => v.RuleFor(x => x.LastName).NotNull(),
v => v.RuleFor(x => x.Email).NotNull(),
v => v.RuleFor(x => x.Age)
.GreaterThanOrEqualTo(18)
.WithMessage("Must be 18 or older")
};
}
Separate Validator Class
For complex validation logic, create a dedicated validator:
public class UserValidator : AbstractValidator<User>
{
public UserValidator()
{
RuleFor(x => x.FirstName)
.NotNull()
.WithMessage("First name is required");
RuleFor(x => x.LastName)
.NotNull()
.WithMessage("Last name is required");
RuleFor(x => x.Email)
.NotNull()
.EmailAddress()
.WithMessage("Valid email address is required");
RuleFor(x => x.Age)
.GreaterThanOrEqualTo(18)
.WithMessage("Must be 18 or older")
.LessThan(120)
.WithMessage("Age must be realistic");
}
}
public class User
{
private static readonly UserValidator Validator = new();
public static Result<User> TryCreate(
FirstName firstName,
LastName lastName,
EmailAddress email,
int age)
{
var user = new User(firstName, lastName, email, age);
return Validator.ValidateToResult(user);
}
}
Core Concepts
| Feature | Use Case | Example |
|---|---|---|
| Sync Validation | Simple validation rules | Validator.ValidateToResult(user) |
| Async Validation | Database/API checks | await Validator.ValidateToResultAsync(user, ct) |
| Combine Integration | Multi-step validation | Email.TryCreate().Combine(Name.TryCreate()).Bind(...) |
| Conditional Rules | Context-dependent validation | RuleFor(x => x.Address).When(x => x.NeedsShipping) |
| Custom Messages | Property-specific errors | WithMessage(x => $"Value {x.Price} invalid") |
| RuleSets | Different scenarios | IncludeRuleSets("Create") |
Best Practices
Use InlineValidator for simple cases, AbstractValidator for complex logic with dependencies.
Validate value objects separately from aggregates
First validate value objects, then validate aggregate invariants.Use async validation only when necessary
Database checks and API calls justify async, simple format checks do not.Provide meaningful error messages with context
UseWithMessage(x => ...)to include property values in error messages.Use When() for conditional validation
Apply rules based on object state or external conditions.Leverage RuleSets for different validation scenarios
Separate validation rules for Create, Update, Delete operations.Combine FluentValidation with ROP
Use FluentValidation for structure/format, ROP Ensure for business rules.
Resources
- SAMPLES.md - Comprehensive examples and advanced patterns
- FluentValidation Documentation - Official FluentValidation docs
- Railway Oriented Programming - Core Result<T> concepts
- Domain-Driven Design - Entity and value object patterns
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. 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. |
-
net10.0
- FluentValidation (>= 12.1.1)
- FunctionalDdd.RailwayOrientedProgramming (>= 3.0.0-alpha.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated | |
|---|---|---|---|
| 3.0.0-alpha.20 | 34 | 1/6/2026 | |
| 3.0.0-alpha.19 | 39 | 1/5/2026 | |
| 3.0.0-alpha.13 | 37 | 1/5/2026 | |
| 3.0.0-alpha.9 | 40 | 1/5/2026 | |
| 3.0.0-alpha.3 | 153 | 12/20/2025 | |
| 2.1.10 | 674 | 12/3/2025 | |
| 2.1.9 | 270 | 11/21/2025 | |
| 2.1.1 | 211 | 4/26/2025 | |
| 2.1.0-preview.3 | 89 | 4/26/2025 | |
| 2.0.1 | 209 | 1/23/2025 | |
| 2.0.0-alpha.62 | 87 | 1/8/2025 | |
| 2.0.0-alpha.61 | 79 | 1/7/2025 | |
| 2.0.0-alpha.60 | 97 | 12/7/2024 | |
| 2.0.0-alpha.55 | 108 | 11/22/2024 | |
| 2.0.0-alpha.52 | 124 | 11/7/2024 | |
| 2.0.0-alpha.48 | 87 | 11/2/2024 | |
| 2.0.0-alpha.44 | 176 | 10/18/2024 | |
| 2.0.0-alpha.42 | 125 | 10/14/2024 | |
| 2.0.0-alpha.39 | 119 | 6/27/2024 | |
| 2.0.0-alpha.38 | 105 | 4/24/2024 | |
| 2.0.0-alpha.33 | 132 | 4/17/2024 | |
| 2.0.0-alpha.26 | 157 | 4/9/2024 | |
| 2.0.0-alpha.21 | 140 | 4/1/2024 | |
| 2.0.0-alpha.19 | 104 | 3/5/2024 | |
| 2.0.0-alpha.18 | 131 | 2/28/2024 | |
| 2.0.0-alpha.17 | 131 | 2/26/2024 | |
| 2.0.0-alpha.15 | 113 | 1/30/2024 | |
| 2.0.0-alpha.8 | 120 | 1/27/2024 | |
| 2.0.0-alpha.6 | 144 | 1/5/2024 | |
| 1.1.1 | 892 | 11/15/2023 | |
| 1.1.0-alpha.32 | 169 | 11/2/2023 | |
| 1.1.0-alpha.30 | 264 | 10/31/2023 | |
| 1.1.0-alpha.28 | 129 | 10/28/2023 | |
| 1.1.0-alpha.27 | 133 | 10/28/2023 | |
| 1.1.0-alpha.24 | 106 | 10/20/2023 | |
| 1.1.0-alpha.23 | 153 | 10/13/2023 | |
| 1.1.0-alpha.21 | 151 | 10/1/2023 | |
| 1.1.0-alpha.20 | 117 | 9/30/2023 | |
| 1.1.0-alpha.19 | 147 | 9/30/2023 | |
| 1.1.0-alpha.18 | 137 | 9/29/2023 | |
| 1.1.0-alpha.17 | 151 | 9/22/2023 | |
| 1.1.0-alpha.13 | 126 | 9/16/2023 | |
| 1.1.0-alpha.4 | 234 | 6/9/2023 | |
| 1.1.0-alpha.3 | 171 | 6/8/2023 | |
| 1.0.1 | 774 | 5/12/2023 | |
| 0.1.0-alpha.40 | 239 | 4/6/2023 | |
| 0.1.0-alpha.39 | 216 | 4/3/2023 | |
| 0.1.0-alpha.38 | 259 | 4/2/2023 | |
| 0.1.0-alpha.37 | 228 | 3/31/2023 | |
| 0.1.0-alpha.35 | 236 | 3/29/2023 | |
| 0.1.0-alpha.34 | 215 | 3/28/2023 | |
| 0.1.0-alpha.32 | 237 | 3/18/2023 | |
| 0.1.0-alpha.30 | 223 | 3/11/2023 | |
| 0.1.0-alpha.27 | 268 | 3/7/2023 | |
| 0.1.0-alpha.24 | 240 | 2/15/2023 | |
| 0.1.0-alpha.22 | 223 | 2/15/2023 | |
| 0.1.0-alpha.20 | 230 | 2/13/2023 | |
| 0.1.0-alpha.19 | 188 | 2/13/2023 | |
| 0.0.1-alpha.14 | 238 | 1/4/2023 | |
| 0.0.1-alpha.4 | 222 | 12/30/2022 | |
| 0.0.1-alpha | 812 | 12/21/2022 |