Nedo.AspNet.Common.Validation.Fluent
1.9.1
dotnet add package Nedo.AspNet.Common.Validation.Fluent --version 1.9.1
NuGet\Install-Package Nedo.AspNet.Common.Validation.Fluent -Version 1.9.1
<PackageReference Include="Nedo.AspNet.Common.Validation.Fluent" Version="1.9.1" />
<PackageVersion Include="Nedo.AspNet.Common.Validation.Fluent" Version="1.9.1" />
<PackageReference Include="Nedo.AspNet.Common.Validation.Fluent" />
paket add Nedo.AspNet.Common.Validation.Fluent --version 1.9.1
#r "nuget: Nedo.AspNet.Common.Validation.Fluent, 1.9.1"
#:package Nedo.AspNet.Common.Validation.Fluent@1.9.1
#addin nuget:?package=Nedo.AspNet.Common.Validation.Fluent&version=1.9.1
#tool nuget:?package=Nedo.AspNet.Common.Validation.Fluent&version=1.9.1
Nedo.AspNet.Common.Validation.Fluent
A fluent, type-safe API for defining validation rules on top of Nedo.AspNet.Common.Validation.Core. Inherit from AbstractValidator<T>, chain rules with RuleFor(), and get an IValidator<T> you can compose, inject, or test.
Install
dotnet add package Nedo.AspNet.Common.Validation.Fluent
Quick Start
using Nedo.AspNet.Common.Validation.Fluent;
public class UserValidator : AbstractValidator<UserInput>
{
public UserValidator()
{
RuleFor(x => x.Name)
.Required()
.MinLength(3)
.MaxLength(100)
.Alpha();
RuleFor(x => x.Email)
.Required()
.Matches(@"^[^@\s]+@[^@\s]+\.[^@\s]+$");
RuleFor(x => x.Age)
.Required()
.GreaterThanOrEqual(18)
.LessThanOrEqual(65);
RuleFor(x => x.EmployeeCode)
.Required()
.NoWhitespace()
.UpperCase()
.StartsWith("EMP");
}
}
// Usage
var validator = new UserValidator();
var result = validator.Validate(user, "id"); // Indonesian locale
if (!result.IsValid)
foreach (var e in result.Errors)
Console.WriteLine($"[{e.Code}] {e.Message}");
Architecture
AbstractValidator<T> ──implements──▶ IValidator<T>
│
└── RuleFor(x => x.Prop) → RuleBuilder<T, TProp>
│
├── .Required() → RequiredValidator
├── .MinLength(n) → MinLengthValidator
├── .Alpha() → AlphaValidator
├── .GreaterThanOrEqual() → MinValueValidator
└── .Must(custom) → User-defined lambda
Each extension method internally delegates to the corresponding static validator from Nedo.AspNet.Common.Validation.Core. This means:
- Same error codes — Fluent rules produce identical
ValidationErrorcodes as calling Core validators directly - Same localization — Culture-aware messages are resolved through the same
.resxresources - Zero duplication — No separate validation logic; the Fluent layer is a thin wrapper
Available Extensions
General Extensions
| Method | Core Validator | Error Code | Description |
|---|---|---|---|
.Required() |
RequiredValidator |
VAL-GEN-001 |
Not null, empty, or default |
.MinLength(n) |
MinLengthValidator |
VAL-GEN-002 |
Minimum character length |
.MaxLength(n) |
MaxLengthValidator |
VAL-GEN-003 |
Maximum character length |
.ExactLength(n) |
ExactLengthValidator |
VAL-GEN-004 |
Exact character length |
.Matches(regex) |
RegexValidator |
VAL-GEN-006 |
Regular expression match |
String Extensions
| Method | Core Validator | Error Code | Description |
|---|---|---|---|
.Alpha() |
AlphaValidator |
VAL-STR-007 |
Letters only (A–Z, a–z) |
.AlphaNumeric() |
AlphaNumericValidator |
VAL-STR-010 |
Letters and digits only |
.NoWhitespace() |
NoWhitespaceValidator |
VAL-STR-001 |
No spaces/tabs |
.NoSpecialCharacter() |
NoSpecialCharacterValidator |
VAL-STR-008 |
No symbols or punctuation |
.UpperCase() |
UpperCaseOnlyValidator |
VAL-STR-011 |
All uppercase |
.LowerCase() |
LowerCaseOnlyValidator |
VAL-STR-012 |
All lowercase |
.StartsWith(s) |
StartsWithValidator |
VAL-STR-003 |
Begins with prefix |
.EndsWith(s) |
EndsWithValidator |
VAL-STR-004 |
Ends with suffix |
.Contains(s) |
ContainsValidator |
VAL-STR-005 |
Contains substring |
.NotContains(s) |
NotContainsValidator |
VAL-STR-006 |
Excludes substring |
Numeric Extensions
For Nullable<T> properties where T : INumber<T> (int?, decimal?, double?, etc.):
| Method | Core Validator | Error Code | Description |
|---|---|---|---|
.GreaterThanOrEqual(n) |
MinValueValidator |
VAL-NUM-001 |
Value ≥ n |
.LessThanOrEqual(n) |
MaxValueValidator |
VAL-NUM-002 |
Value ≤ n |
.Range(min, max) |
RangeValidator |
VAL-NUM-003 |
min ≤ value ≤ max |
.Positive() |
PositiveNumberValidator |
VAL-NUM-005 |
Value > 0 |
.Negative() |
NegativeNumberValidator |
VAL-NUM-006 |
Value < 0 |
.NonZero() |
NonZeroValidator |
VAL-NUM-008 |
Value ≠ 0 |
.DivisibleBy(n) |
DivisibleByValidator |
VAL-NUM-011 |
Value % n == 0 |
Custom Rules
Use .Must() to add inline validation logic that isn't covered by built-in extensions:
Lambda with Error Details
RuleFor(x => x.Field).Must((value, fieldName, culture) =>
{
if (value == null) return null; // let Required() handle nulls
return value.StartsWith("VALID-")
? null
: new ValidationError("CUSTOM-001", $"{fieldName} must start with VALID-", new[] { fieldName });
});
Simple Predicate
RuleFor(x => x.Code).Must(
predicate: value => value.Length == 8,
errorCode: "CUSTOM-002",
errorMessage: "Code must be exactly 8 characters");
Localization
AbstractValidator<T>.Validate() accepts an optional culture parameter. This culture is passed down to every Core validator call, so messages are automatically resolved from the appropriate .resx file:
var validator = new UserValidator();
// English messages
var resultEn = validator.Validate(user, "en");
// Indonesian messages
var resultId = validator.Validate(user, "id");
// Default culture (English) when omitted
var resultDefault = validator.Validate(user);
Composing with Other Validators
AbstractValidator<T> implements IValidator<T>, so it works seamlessly with CompositeValidator<T> from the Core package:
using Nedo.AspNet.Common.Validation.Core;
// Combine Fluent + DSL + inline rules
var composite = new CompositeValidator<UserInput>()
.Add(new UserValidator()) // Fluent validator
.Add(dslCompiledValidator) // DSL-compiled validator
.Add((user, culture) => // Inline rule
RequiredValidator.Validate(user.Name, "Name", culture ?? "en"));
var result = composite.Validate(user, "id");
Dependency Injection
Register your validators in the DI container and inject them where needed:
// Registration
services.AddSingleton<IValidator<UserInput>, UserValidator>();
services.AddSingleton<IValidator<OrderInput>, OrderValidator>();
// Usage in a controller or service
public class UserService
{
private readonly IValidator<UserInput> _validator;
public UserService(IValidator<UserInput> validator)
=> _validator = validator;
public ValidationResult ValidateUser(UserInput input, string culture)
=> _validator.Validate(input, culture);
}
Related Packages
- Nedo.AspNet.Common.Validation.Core — Core engine, 120+ static validators,
CompositeValidator<T> - Nedo.AspNet.Common.Validation.Dsl — Text-based DSL for runtime rule definitions
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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. |
-
net9.0
- Nedo.AspNet.Common.Validation.Core (>= 1.9.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.