Verifast 1.0.0
dotnet add package Verifast --version 1.0.0
NuGet\Install-Package Verifast -Version 1.0.0
<PackageReference Include="Verifast" Version="1.0.0" />
<PackageVersion Include="Verifast" Version="1.0.0" />
<PackageReference Include="Verifast" />
paket add Verifast --version 1.0.0
#r "nuget: Verifast, 1.0.0"
#:package Verifast@1.0.0
#addin nuget:?package=Verifast&version=1.0.0
#tool nuget:?package=Verifast&version=1.0.0
Verifast
High‑performance, allocation‑friendly validation for .NET 9 and netstandard (2.1/2.0). No complicated APIs, no expression trees - just plain C#. Implement a tiny interface, add errors or warnings, and you’re done.
Why Verifast
- Minimal API: implement
IValidator<T>orIAsyncValidator<T>and write ordinary C#. - Fast by design: struct based
ValidationResult<TMessage>allocates only when you add messages. - Ergonomic helpers: call
.Validate(...)for a result or.TryValidate(...)for a quick bool. - Plays well with
ref struct: APIs are designed to enable stack‑only scenarios. - Your messages, your way: use
stringor a customTMessagefor richer metadata.
Benchmarks
BenchmarkDotNet results comparing Verifast to FluentValidation (baseline, industry standard). Full report: BenchmarkRun-joined.md.
| Type | Method | ValidDto | Mean | Ratio | Allocated | Alloc Ratio |
|---|---|---|---|---|---|---|
| AsyncValidation | FluentValidation | False | 10,935.2 ns | baseline | 14104 B | |
| AsyncValidation | Verifast | False | 2,203.2 ns | 4.96x faster | 1096 B | 12.87x less |
| AsyncValidation | FluentValidation | True | 8,470.8 ns | baseline | 9808 B | |
| AsyncValidation | Verifast | True | 2,101.9 ns | 5.20x faster | 1016 B | 13.88x less |
| SyncValidation | FluentValidation | False | 35,687.7 ns | baseline | 63112 B | |
| SyncValidation | Verifast | False | 141.4 ns | 252.377x faster | 328 B | 192.415x less |
| SyncValidation | FluentValidation | True | 26,091.2 ns | baseline | 50063 B | |
| SyncValidation | Verifast | True | 112.3 ns | 320.264x faster | - | NA |
Install
dotnet add package Verifast
Quick Start
Define your model and implement its validator. Then call the extension helpers.
using Verifast;
public readonly record struct User(string? Name, int Age);
public readonly struct UserValidator : IValidator<User> {
public void Validate(in User instance, ref ValidationResult<string> result) {
if (string.IsNullOrWhiteSpace(instance.Name))
result.AddError("'Name' must be non-empty");
if (instance.Age is < 18 or > 120)
result.AddError("'Age' must be between 18 and 120");
}
}
var user = new User("Ada", 33);
var validator = new UserValidator();
var result = validator.Validate(user);
if (!result.IsValid)
foreach (var error in result.Errors) Console.WriteLine(error);
Or get a simple pass/fail while still capturing details:
if (!validator.TryValidate(user, out var result))
foreach (var error in result.Errors) Console.WriteLine(error);
Async Validation
Prefer async? Implement IAsyncValidator<T> and return a ValueTask<ValidationResult<TMessage>>.
public record AsyncUser(string? Email);
public sealed class AsyncUserValidator : IAsyncValidator<AsyncUser> {
public async ValueTask<ValidationResult<string>> ValidateAsync(AsyncUser instance, CancellationToken ct = default) {
await Task.Yield(); // e.g., call a store or service
ValidationResult<string> result = default;
if (!string.IsNullOrWhiteSpace(instance.Email))
if (!LooksLikeEmail(instance.Email!))
result.AddError("'Email' must be a valid email");
return result;
static bool LooksLikeEmail(string s) {
int at = s.IndexOf('@');
if (at <= 0 || at >= s.Length - 1) return false;
int dot = s.IndexOf('.', at + 1);
if (dot <= at + 1 || dot >= s.Length - 1) return false;
return true;
}
}
}
Custom Message Types
Avoid string allocations or carry structured metadata by choosing your own TMessage.
using Verifast;
public readonly record struct Msg(string Code, string Text);
public readonly struct EvenValidator : IValidator<int, Msg> {
public void Validate(in int value, ref ValidationResult<Msg> result) {
if ((value & 1) != 0)
result.AddError(new Msg("NotEven", "Value must be even"));
}
}
if (!new EvenValidator().TryValidate(3, out var res))
foreach (var e in res.Errors) Console.WriteLine($"{e.Code}: {e.Text}");
Design Philosophy
- Pure language constructs: write straightforward
if/forstatements - no fluent builders, no new mental model, onboarding takes minutes. - Allocation‑aware: messages are captured on demand; zero allocations when data is valid.
License
MIT - see LICENSE.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 is compatible. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- System.Threading.Tasks.Extensions (>= 4.6.3)
-
.NETStandard 2.1
- No dependencies.
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
Added support for netstandard2.0 and netstandard2.1.