ValidationModules.Runtime 1.0.0-rc1006

This is a prerelease version of ValidationModules.Runtime.
dotnet add package ValidationModules.Runtime --version 1.0.0-rc1006
                    
NuGet\Install-Package ValidationModules.Runtime -Version 1.0.0-rc1006
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="ValidationModules.Runtime" Version="1.0.0-rc1006" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="ValidationModules.Runtime" Version="1.0.0-rc1006" />
                    
Directory.Packages.props
<PackageReference Include="ValidationModules.Runtime" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add ValidationModules.Runtime --version 1.0.0-rc1006
                    
#r "nuget: ValidationModules.Runtime, 1.0.0-rc1006"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package ValidationModules.Runtime@1.0.0-rc1006
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=ValidationModules.Runtime&version=1.0.0-rc1006&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=ValidationModules.Runtime&version=1.0.0-rc1006&prerelease
                    
Install as a Cake Tool

ValidationModules

Compile-time validation for .NET. Rules are declared as attributes and flattened into straight-line C# by a source generator at build time. No reflection, no expression trees, no regex compiled at runtime — Native AOT is a hard requirement rather than a supported configuration.

public record Pet {
    [Required]
    [StringLength(min: 1, max: 100)]
    public string Name { get; init; }

    [Pattern("^[a-zA-Z0-9-]*$")]
    public string? Sku { get; init; }

    [ValidateNested]
    public Address? Home { get; init; }

    [ItemCount(min: 1, max: 10), ValidateNested]
    public IReadOnlyList<Toy> Toys { get; init; } = [];
}
var result = validator.Validate(pet);

foreach (var error in result.Errors) {
    Console.WriteLine($"{error.Field}: {error.Code}");
}
// name             required
// home.postalCode  required
// toys[3].name     required

Why

FluentValidation compiles expression trees at runtime. Under Native AOT Expression.Compile() falls back to the LINQ interpreter rather than throwing, so it works — but property access is interpreted and you carry IL2026/IL3050 trim warnings. For a workload where AOT is a requirement, that is the gap this fills.

ValidationModules.Runtime carries IsAotCompatible and escalates IL2026;IL2055;IL2067;IL2072; IL2075;IL2087;IL3050 to errors, so the constraint is enforced by the compiler rather than by review.

Status

Release candidate for 1.0.0. Built so far:

Stage
1 Runtime — contracts, context, error model, constraint attributes, naming done
2 Generator, no profiles done
3 Profiles deferred past 1.0.0
4 Impl packaging for framework authors done
5 Hardened integration substantially done
6 FluentValidation adapter and conformance suite not started
ASP.NET Core integration done

Also built since the plan was written, and not in its staging: a declarative rule-class front end (IValidationRulesFor<T>, API-SURFACE.md §19) and a DataAnnotations front end (§18).

Profiles and overlays are deferred past 1.0.0, and their declaration surfaces have been withdrawn. Both shipped before the features behind them: using a profile argument was VM0019, an error, and [ValidationOverlayFor<T>] was read by nothing at all. A 1.0.0 pins the public surface, and members whose only behaviour is a build failure — or no behaviour whatsoever — are the wrong thing to pin. Every removal is additively reversible; docs/deferred-features.md records the analysis, including the one member set that needs default interface methods to come back without breaking implementers.

Every declared diagnostic now has a report site. DiagnosticCatalogueTests fails in both directions, so a new descriptor without one cannot ship.

Documentation

The docs site lives in website/ and publishes to https://ipjohnson.github.io/ValidationModules/:

cd website && npm install && npm run dev

Dead internal links fail the build, so a rename cannot rot a link silently.

Design

  • IMPLEMENTATION-PLAN.md — what is being built and why. A specification, not a discussion document.
  • API-SURFACE.md — the exact public surface, the reasoning behind each decision, and the verification log behind the claims.

The single most consequential decision is in API-SURFACE.md §13.1: ValidationContext is a readonly struct rather than a ref struct, carrying its own path rather than indexing into shared storage. That is what lets IAsyncValidatorFor<T> take the same context as the synchronous side, and what makes a context safe to hold across an await or hand to a concurrent branch.

Packages

Package Ships as Referenced by
ValidationModules.Runtime lib/ application code
ValidationModules.SourceGenerator analyzers/dotnet/cs application code, PrivateAssets=all
ValidationModules.AspNetCore lib/ web applications
ValidationModules.SourceGenerator.Impl source-only framework authors
ValidationModules.FluentValidation lib/ planned adapter
ValidationModules.Testing lib/ planned conformance suite

ValidationModules.Runtime depends only on Microsoft.Extensions.DependencyInjection.Abstractions, framework-matched per TFM. It does not reference DependencyModules.Runtime — the library is DependencyModules-shaped in its ergonomics, but only the generated module needs DM types, and that lands in the consumer's assembly, which already references DM.

Building

dotnet build --configuration Release
dotnet test  --configuration Release
dotnet test  --configuration Release --collect:"XPlat Code Coverage" --settings coverlet.runsettings

The public API is pinned by a snapshot at tests/ValidationModules.Runtime.Tests/Snapshots/PublicApiTests.RuntimeApi.verified.txt — one file listing every public type and member, which is also the quickest way to read the surface. To accept an intended change:

UPDATE_SNAPSHOTS=1 dotnet test tests/ValidationModules.Runtime.Tests

ASP.NET Core

builder.Services.AddMyAppValidators();

app.MapPost("/orders", (CreateOrder order) => Results.Ok())
   .Validate<CreateOrder>();

A failure answers with RFC 9457 before the handler runs, carrying the field paths and the stable codes. The type argument is named rather than inferred, which is what keeps the request path free of reflection — website/guide/aspnetcore.md covers why, and what the response looks like.

Benchmarks

./scripts/benchmark.sh                     # ValidationModules alone, JIT and Native AOT
./scripts/benchmark.sh --quick             # the same, fast enough to run after a change
./scripts/benchmark.sh --comparative       # against FluentValidation and DataAnnotations

Two suites. The default one measures this library on its own and is what a change should be checked against; the comparative one is opt-in, because its numbers move when FluentValidation changes as well as when this does. benchmarks/README.md covers what each measures, and the four choices the comparative suite makes in FluentValidation's favour so the comparison stays honest.

License

MIT.

Product Compatible and additional computed target framework versions.
.NET 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 was computed.  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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages (2)

Showing the top 2 NuGet packages that depend on ValidationModules.Runtime:

Package Downloads
Hardened.Requests.Runtime

Execution pipeline implementation for Hardened: filters, serialization, parameter validation and error handling.

ValidationModules.AspNetCore

ASP.NET Core integration for ValidationModules: an endpoint filter that validates minimal API arguments before the handler runs, an RFC 9457 ProblemDetails mapping for ValidationResult, and an exception handler for ValidationException. No reflection, Native AOT safe.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0-rc1006 162 8/16/2026
1.0.0-rc1005 54 8/16/2026
1.0.0-rc1004 52 8/16/2026
1.0.0-rc1003 188 8/14/2026
1.0.0-rc1002 55 8/14/2026
0.1.0-alpha.1 106 8/13/2026