SkillAgentSearch skills...

Validot

Validot is a performance-first, compact library for advanced model validation. Using a simple declarative fluent interface, it efficiently handles classes, structs, nested members, collections, nullables, plus any relation or combination of them. It also supports translations, custom logic extensions with tests, and DI containers.

Install / Use

/learn @bartoszlenar/Validot
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<h1 align="center"> <br /> <img src="../assets/logo/validot-logo.svg" height="256px" width="256px" /> <br /> Validot <br /> </h1> <p align="center">Validot is a performance-first, compact library for advanced model validation. Using a simple declarative fluent interface, it efficiently handles classes, structs, nested members, collections, nullables, plus any relation or combination of them. It also supports translations, custom logic extensions with tests, and DI containers.</p> <br /> <p align="center"> <a href="https://www.nuget.org/packages/Validot"> <img src="https://img.shields.io/nuget/v/Validot?style=for-the-badge&logo=nuget&logoColor=white&logoWidth=20&label=CURRENT%20VERSION"> </a> <a href="https://www.nuget.org/packages/Validot"> <img src="https://img.shields.io/github/release-date/bartoszlenar/Validot?include_prereleases&style=for-the-badge&label=RELEASED"> </a> </p> <!-- <p align="center"> <a href="https://github.com/bartoszlenar/Validot/commits/main"> <img src="https://img.shields.io/github/commits-since/bartoszlenar/Validot/v2.4.1/main?logo=git&logoColor=white&style=flat-square"> </a> <a href="https://github.com/bartoszlenar/Validot/commits/main"> <img src="https://img.shields.io/github/last-commit/bartoszlenar/Validot/main?style=flat-square"> </a> <a href="https://github.com/bartoszlenar/Validot/actions?query=branch%3Amain+workflow%3ACI"> <img src="https://img.shields.io/github/actions/workflow/status/bartoszlenar/Validot/CI.yml?branch=main&style=flat-square&label=build&logo=github&logoColor=white&logoWidth=20"> </a> <a href="https://codecov.io/gh/bartoszlenar/Validot/branch/main"> <img src="https://img.shields.io/codecov/c/gh/bartoszlenar/Validot/main?style=flat-square&logo=codecov&logoColor=white&logoWidth=20"> </a> </p> --> <!-- <p align="center"> <a href="https://github.com/bartoszlenar/Validot/releases"> <img src="https://img.shields.io/github/v/release/bartoszlenar/Validot?include_prereleases&style=for-the-badge&label=latest%20pre-release%20version&logo=nuget&logoColor=white&logoWidth=20"> </a> </p> --> <div align="center"> <h3> <a href="#quickstart"> Quickstart </a> | <a href="#features"> Features </a> | <a href="#project-info"> Project info </a> | <a href="../docs/DOCUMENTATION.md"> Documentation </a> | <a href="../docs/CHANGELOG.md"> Changelog </a> </div> <p align="center"> <a href="#validot-vs-fluentvalidation"> 🔥⚔️ Validot vs FluentValidation ⚔️🔥 </a> </br> </br> <a href="../docs/articles/validots-performance-explained.md"> 📜 Article: Validot's performance explained </a> </br> <a href="../docs/articles/crafting-model-specifications-using-validot.md"> 📜 Article: Crafting model specifications using Validot </a> </p> <p align="center"> Built with 🤘🏻by <a href="https://lenar.dev">Bartosz Lenar</a> </p> </br>

Announcement! Validot is archived!

Validot has been my public pet project since 2020, a proof-of-concept turned into a standalone, fully-featured NuGet library. Its core focus is on performance and a low-allocation approach. On release day, Validot was 2.5 times faster while consuming 8 times less memory than the industry's gold standard: FluentValidation! I pushed dotnet memory performance and optimizations to their limits. And I'm proud of my work.

Given my daily responsibilities and other coding projects, I have to confess that it seems improbable I'll have time to keep working on Validot.

I appreciate all the contributors, and especially, I extend my gratitude to Jeremy Skinner for his work on FluentValidation. I genuinely believe I played a role in the open source community by motivating Jeremy to enhance FluentValidation's performance.

Quickstart

Add the Validot nuget package to your project using dotnet CLI:

dotnet add package Validot

All the features are accessible after referencing single namespace:

using Validot;

And you're good to go! At first, create a specification for your model with the fluent api.

Specification<UserModel> specification = _ => _
    .Member(m => m.Email, m => m
        .Email()
        .WithExtraCode("ERR_EMAIL")
        .And()
        .MaxLength(100)
    )
    .Member(m => m.Name, m => m
        .Optional()
        .And()
        .LengthBetween(8, 100)
        .And()
        .Rule(name => name.All(char.IsLetterOrDigit))
        .WithMessage("Must contain only letter or digits")
    )
    .And()
    .Rule(m => m.Age >= 18 || m.Name != null)
    .WithPath("Name")
    .WithMessage("Required for underaged user")
    .WithExtraCode("ERR_NAME");

The next step is to create a validator. As its name stands - it validates objects according to the specification. It's also thread-safe so you can seamlessly register it as a singleton in your DI container.

var validator = Validator.Factory.Create(specification);

Validate the object!

var model = new UserModel(email: "inv@lidv@lue", age: 14);

var result = validator.Validate(model);

The result object contains all information about the errors. Without retriggering the validation process, you can extract the desired form of an output.

result.AnyErrors; // bool flag:
// true

result.MessageMap["Email"] // collection of messages for "Email":
// [ "Must be a valid email address" ]

result.Codes; // collection of all the codes from the model:
// [ "ERR_EMAIL", "ERR_NAME" ]

result.ToString(); // compact printing of codes and messages:
// ERR_EMAIL, ERR_NAME
//
// Email: Must be a valid email address
// Name: Required for underaged user

Features

Advanced fluent API, inline

No more obligatory if-ology around input models or separate classes wrapping just validation logic. Write specifications inline with simple, human-readable fluent API. Native support for properties and fields, structs and classes, nullables, collections, nested members, and possible combinations.

Specification<string> nameSpecification = s => s
    .LengthBetween(5, 50)
    .SingleLine()
    .Rule(name => name.All(char.IsLetterOrDigit));

Specification<string> emailSpecification = s => s
    .Email()
    .And()
    .Rule(email => email.All(char.IsLower))
    .WithMessage("Must contain only lower case characters");

Specification<UserModel> userSpecification = s => s
    .Member(m => m.Name, nameSpecification)
    .WithMessage("Must comply with name rules")
    .And()
    .Member(m => m.PrimaryEmail, emailSpecification)
    .And()
    .Member(m => m.AlternativeEmails, m => m
        .Optional()
        .And()
        .MaxCollectionSize(3)
        .WithMessage("Must not contain more than 3 addresses")
        .And()
        .AsCollection(emailSpecification)
    )
    .And()
    .Rule(user => {

        return user.PrimaryEmail is null || user.AlternativeEmails?.Contains(user.PrimaryEmail) == false;

    })
    .WithMessage("Alternative emails must not contain the primary email address");

Validators

Compact, highly optimized, and thread-safe objects to handle the validation.

Specification<BookModel> bookSpecification = s => s
    .Optional()
    .Member(m => m.AuthorEmail, m => m.Optional().Email())
    .Member(m => m.Title, m => m.NotEmpty().LengthBetween(1, 100))
    .Member(m => m.Price, m => m.NonNegative());

var bookValidator =  Validator.Factory.Create(bookSpecification);

services.AddSingleton<IValidator<BookModel>>(bookValidator);
var bookModel = new BookModel() { AuthorEmail = "inv@lid_em@il", Price = 10 };

bookValidator.IsValid(bookModel);
// false

bookValidator.Validate(bookModel).ToString();
// AuthorEmail: Must be a valid email address
// Title: Required

bookValidator.Validate(bookModel, failFast: true).ToString();
// AuthorEmail: Must be a valid email address

bookValidator.Template.ToString(); // Template contains all of the possible errors:
// AuthorEmail: Must be a valid email address
// Title: Required
// Title: Must not be empty
// Title: Must be between 1 and 100 characters in length
// Price: Must not be negative

Results

Whatever you want. Error flag, compact list of codes, or detailed maps of messages and codes. With sugar on top: friendly ToString() printing that contains everything, nicely formatted.

var validationResult = validator.Validate(signUpModel);

if (validationResult.AnyErrors)
{
    // check if a specific code has been recorded for Email property:
    if (validationResult.CodeMap["Email"].Contains("DOMAIN_BANNED"))
    {
        _actions.NotifyAboutDomainBanned(signUpModel.Email);
    }

    var errorsPrinting = validationResult.ToString();

    // save all message

Related Skills

View on GitHub
GitHub Stars341
CategoryProduct
Updated2mo ago
Forks25

Languages

C#

Security Score

100/100

Audited on Jan 15, 2026

No findings