ArturRios.Validation
2.0.0
dotnet add package ArturRios.Validation --version 2.0.0
NuGet\Install-Package ArturRios.Validation -Version 2.0.0
<PackageReference Include="ArturRios.Validation" Version="2.0.0" />
<PackageVersion Include="ArturRios.Validation" Version="2.0.0" />
<PackageReference Include="ArturRios.Validation" />
paket add ArturRios.Validation --version 2.0.0
#r "nuget: ArturRios.Validation, 2.0.0"
#:package ArturRios.Validation@2.0.0
#addin nuget:?package=ArturRios.Validation&version=2.0.0
#tool nuget:?package=ArturRios.Validation&version=2.0.0
ArturRios.Validation
ArturRios.Validation โ a thin, opinionated model-validation layer for .NET built on top of
FluentValidation. It wraps FluentValidation's AbstractValidator<T>
in a FluentValidator<T> base class that turns validation results into the shapes an application actually
consumes: a plain array of error messages, or an ArturRios.Output
ProcessOutput / DataOutput<T> envelope โ with optional stripping of the quotes and periods that
FluentValidation puts in its default messages.
- ๐ Full documentation: https://artur-rios.github.io/dotnet-validation
What you get
| Type | What it does |
|---|---|
FluentValidator<T> |
Base validator: subclass it, declare RuleFor(...) rules in the constructor, get error/Output helpers for free. |
IFluentValidator<T> |
Abstraction over FluentValidator<T> (extends FluentValidation's IValidator<T>) for DI and testing. |
Every helper has an asynchronous counterpart taking a CancellationToken. Reach for those whenever the
validator declares an asynchronous rule โ MustAsync, CustomAsync and the like โ because
FluentValidation refuses to run one from a synchronous call and throws
AsyncValidatorInvokedSynchronouslyException instead.
IFluentValidator<T> is contravariant in T, so a validator for a base type can stand in for one of a
derived type. That is also why ValidateAndReturnDataOutput is not on the interface: it returns a
DataOutput<T>, which puts T in an output position, and contravariance forbids that. Take the concrete
FluentValidator<T> when the validated model has to come back inside the envelope.
classDiagram
class IValidator~T~ {
<<interface>>
}
class IFluentValidator~T~ {
<<interface>>
+ValidateAndReturnErrors(T model, bool removeSpecialChars) string[]
+ValidateAndReturnProcessOutput(T model, bool removeSpecialChars) ProcessOutput
+ValidateAndReturnErrorsAsync(T model, bool removeSpecialChars, CancellationToken ct) Task~string[]~
+ValidateAndReturnProcessOutputAsync(T model, bool removeSpecialChars, CancellationToken ct) Task~ProcessOutput~
}
class AbstractValidator~T~ {
+Validate(T model) ValidationResult
+ValidateAsync(T model, CancellationToken ct) Task~ValidationResult~
}
class FluentValidator~T~ {
+ValidateAndReturnErrors(T model, bool removeSpecialChars) string[]
+ValidateAndReturnProcessOutput(T model, bool removeSpecialChars) ProcessOutput
+ValidateAndReturnDataOutput(T model, bool removeSpecialChars) DataOutput~T~
+ValidateAndReturnErrorsAsync(T model, bool removeSpecialChars, CancellationToken ct) Task~string[]~
+ValidateAndReturnProcessOutputAsync(T model, bool removeSpecialChars, CancellationToken ct) Task~ProcessOutput~
+ValidateAndReturnDataOutputAsync(T model, bool removeSpecialChars, CancellationToken ct) Task~DataOutput~T~~
}
IValidator~T~ <|-- IFluentValidator~T~
AbstractValidator~T~ <|-- FluentValidator~T~
IFluentValidator~T~ <|.. FluentValidator~T~
Installation
dotnet add package ArturRios.Validation
Targets .NET 10. It pulls in FluentValidation and ArturRios.Output transitively.
Quick start
- Define a model and a validator, declaring rules exactly as you would with FluentValidation:
using ArturRios.Validation;
using FluentValidation;
public class Person
{
public string Name { get; set; } = string.Empty;
public int Age { get; set; }
}
public class PersonValidator : FluentValidator<Person>
{
public PersonValidator()
{
RuleFor(p => p.Name).NotEmpty();
RuleFor(p => p.Age).GreaterThan(0);
}
}
- Validate and consume the result in whichever shape you need:
var validator = new PersonValidator();
var person = new Person { Name = "", Age = 0 };
// a) Just the error messages
string[] errors = validator.ValidateAndReturnErrors(person);
// => [ "'Name' must not be empty.", "'Age' must be greater than '0'." ]
// b) Same, but strip the quotes and periods FluentValidation adds
string[] clean = validator.ValidateAndReturnErrors(person, removeSpecialChars: true);
// => [ "Name must not be empty", "Age must be greater than 0" ]
// c) A ProcessOutput envelope (Success is false when there are errors)
ProcessOutput result = validator.ValidateAndReturnProcessOutput(person);
// d) A DataOutput<T> envelope that also carries the validated model back
DataOutput<Person> dataResult = validator.ValidateAndReturnDataOutput(person);
Every helper accepts the optional removeSpecialChars flag, which removes ' and . from the messages,
and every one has an asynchronous counterpart taking a CancellationToken:
string[] errors = await validator.ValidateAndReturnErrorsAsync(person, cancellationToken: ct);
ProcessOutput result = await validator.ValidateAndReturnProcessOutputAsync(person, cancellationToken: ct);
DataOutput<Person> data = await validator.ValidateAndReturnDataOutputAsync(person, cancellationToken: ct);
Reach for those whenever the validator declares an asynchronous rule โ MustAsync, CustomAsync and the
like. FluentValidation refuses to run one from a synchronous call and throws
AsyncValidatorInvokedSynchronouslyException instead.
Documentation
| Page | What's there |
|---|---|
| Overview | Concepts, the full API surface, and end-to-end examples. |
Testing
The test suite is xUnit, and every test is named with the Given / When / Then pattern. Every test class
carries a Category trait, so the two kinds can be run โ and reported โ separately:
dotnet test src/ArturRios.Validation.sln --filter "Category=Unit"
dotnet test src/ArturRios.Validation.sln --filter "Category=Functional"
Unit tests exercise the code in isolation against test doubles. Functional tests resolve the validator out of a real service collection, behind both contracts, and drive whole request-shaped flows through it. CI runs the two as separate jobs, and both must pass before a pull request can be merged.
Versioning
Semantic Versioning (SemVer). Breaking changes bump the major version; new non-breaking behavior bumps the minor; fixes bump the patch.
Build, test and publish
Use the official .NET CLI to build, test and publish, and Git for source control. Optional helper toolsets: Dotnet Tools ยท Python Dotnet Tools.
Legal Details
Licensed under the MIT License โ see LICENSE.
| 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
- ArturRios.Output (>= 3.2.0)
- FluentValidation (>= 12.1.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.