Skip to content

About

A zero-allocation validation library for .NET. Roslyn source generator wires all rule evaluation at compile time — no reflection, no boxing, no runtime overhead.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

508 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

ZeroAlloc.Validation

NuGet Build codecov License: MIT AOT GitHub Sponsors

Source-generated, attribute-based alternative to FluentValidation for .NET: no reflection, 0 bytes allocated when a model is valid, and NativeAOT-ready.

Why ZeroAlloc.Validation

  • Nothing allocated on the valid path. A passing validation allocates 0 B, asserted by allocation regression tests for flat, nested and collection models. FluentValidation 12 allocates 696–3,528 B for the same models.
  • 22.7–145.0× faster than FluentValidation 12 on the valid path, measured side by side in the same BenchmarkDotNet run.
  • Works under NativeAOT and trimming. The validator is plain generated C#, with no reflection or expression trees; CI publishes and runs a NativeAOT sample on every build.
  • Mistakes surface at compile time. A numeric rule on a string, an [IsInEnum] on a non-enum or a [CustomValidation] method with the wrong signature fails the build, not a request.

Install

dotnet add package ZeroAlloc.Validation

The source generator ships inside this package; nothing else is required.

Quick start

using System;
using ZeroAlloc.Validation;

var validator = new CreateOrderRequestValidator(); // generated at build time
var result = validator.Validate(new CreateOrderRequest { Reference = "", Amount = 0, Email = "nope" });

if (!result.IsValid)
    foreach (ref readonly var f in result.Failures)
        Console.WriteLine($"{f.PropertyName}: {f.ErrorMessage}");

[Validate]
public class CreateOrderRequest
{
    [NotEmpty, MaxLength(50)] public string  Reference { get; set; } = "";
    [GreaterThan(0)]          public decimal Amount    { get; set; }
    [NotEmpty, EmailAddress]  public string  Email     { get; set; } = "";
}

Mark a model with [Validate] and the generator writes CreateOrderRequestValidator for you. Running it prints:

Reference: Reference must not be empty.
Amount: Amount must be greater than 0.
Email: Email must be a valid email address.

What you get

  • 20 built-in rules as attributes: emptiness, equality, ranges, lengths, regex, e-mail, enums, precision and scale.
  • Your own rules through reusable attributes, inline [Must] predicates or [CustomValidation] methods.
  • Asynchronous rules, awaited by the generated ValidateAsync.
  • Nested objects and collections, with property paths such as Items[0].Sku in the failures.
  • Rules inherited from base types, conditional rules with When, Unless and [SkipWhen], and short-circuiting with [StopOnFirstFailure].
  • Per-rule severity, Error, Warning or Info, and custom error messages with placeholders.
  • Pipeline behaviors that wrap validation calls, without a per-call allocation.

Optional packages:

Performance

Scenario Speedup vs FluentValidation 12 Allocated (valid)
Flat model 22.7× 0 B vs 664 B
Nested model 100.3× 0 B vs 1,488 B
Collection, 3 items 145.0× 0 B vs 3,528 B

Valid path, FluentValidation 12.2.0, measured 2026-10-21. Allocations are exact. Speed is shown as same-run ratios; absolute timings are not published. On the invalid path ZeroAlloc is 20.9–129.0× faster and allocates 13.0–77.5× less. See Performance for the full results.

Learn more

Related ZeroAlloc packages:

  • ZeroAlloc.Mediator (docs): its ZeroAlloc.Mediator.Validation package runs these validators on every request before the handler.
  • ZeroAlloc.Results (docs): a Mediator request that returns Result<T, ValidationError> gets a failed validation back as a failure result, not an exception.
  • ZeroAlloc.Pipeline (docs): the pipeline-behavior model this library's validator behaviors are built on.
  • ZeroAlloc.Authorization (docs): plugs into the same Mediator pipeline and runs before validation, so a denied caller sees no validation errors.

Contributions are welcome: open an issue or a pull request. Licensed under MIT.

About

A zero-allocation validation library for .NET. Roslyn source generator wires all rule evaluation at compile time — no reflection, no boxing, no runtime overhead.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages