Pitasoft.Validation 5.1.3

dotnet add package Pitasoft.Validation --version 5.1.3
                    
NuGet\Install-Package Pitasoft.Validation -Version 5.1.3
                    
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="Pitasoft.Validation" Version="5.1.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Pitasoft.Validation" Version="5.1.3" />
                    
Directory.Packages.props
<PackageReference Include="Pitasoft.Validation" />
                    
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 Pitasoft.Validation --version 5.1.3
                    
#r "nuget: Pitasoft.Validation, 5.1.3"
                    
#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 Pitasoft.Validation@5.1.3
                    
#: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=Pitasoft.Validation&version=5.1.3
                    
Install as a Cake Addin
#tool nuget:?package=Pitasoft.Validation&version=5.1.3
                    
Install as a Cake Tool

Pitasoft.Validation

A flexible and high-performance C# validation library designed to validate objects using multiple strategies, including Data Annotations, custom rules, and a fluent API.


English

Features

  • Multiple Validation Strategies:
    • Data Annotations: Leverage existing System.ComponentModel.DataAnnotations attributes.
    • Fluent API: Define validation rules using a clean, readable syntax with 25+ built-in methods.
    • Custom Rules: Implement complex validation logic via delegates or custom IChecker implementations.
  • Hierarchical Validation: Support for child validators to validate nested object graphs.
  • Collection Validation: Validate each element of a collection with indexed error paths (Items[0].Name).
  • Conditional Validation: Apply rules only when a condition is met (When / Unless).
  • Asynchronous Validation: Support for async rules via MustAsync and ValidateObjectAsync.
  • Stop on First Failure: Optionally stop evaluating rules for a property after the first failure.
  • Reusable Validators: Define validators as reusable classes using AbstractValidator<T>.
  • Error Codes: Attach optional error codes to rules for programmatic identification.
  • High Performance: Optimized using expression compilation and caching for property access and display names.
  • Pitasoft.Error Integration: Returns errors in the standard ErrorCollection format from the Pitasoft.Error library.
  • Strongly Typed: Full support for generics and lambda expressions to avoid magic strings.

Installation

Add the Pitasoft.Validation package to your project:

dotnet add package Pitasoft.Validation

Note: Depends on Pitasoft.Error.

Getting Started

1. Data Annotations Validation

The simplest way to start is using existing attributes on your models.

public class User
{
    [Required]
    [StringLength(50)]
    public string Name { get; set; }

    [Range(18, 99)]
    public int Age { get; set; }
}

// Usage with Extension Methods (easiest)
var user = new User { Name = "", Age = 10 };
ErrorCollection? errors = user.ValidateWithAttributes();

// Or using a manual validator
var validator = new Validator<User>(new ValidationAttributeChecker<User>());
errors = validator.ValidateObject(user);

if (errors?.Any() == true) 
{
    // Handle errors
}
else
{
    // Valid
}
2. Fluent API Rules

Define rules programmatically without modifying your model classes.

// Usage with Extension Methods
var errors = user.ValidateWithValidator(v => 
{
    v.For(u => u.Name)
        .NotNullOrEmpty("Name is required")
        .MinLength(2, "Name is too short")
        .MaxLength(50, "Name is too long")
        .Matches(@"^[a-zA-Z\s]+$", "Name must contain only letters");

    v.For(u => u.Age)
        .Range(18, 99, "Age must be between 18 and 99");

    v.For(u => u.Email)
        .Email("Invalid email address");
});

// Or using a manual validator
var validator = new Validator<User>();
validator.For(u => u.Name).NotNullOrEmpty("Required");
errors = validator.ValidateObject(user);
3. Nested Objects (Child Validators)

Validate complex object graphs by registering validators for child properties.

public class Order
{
    public Address ShippingAddress { get; set; }
}

var addressValidator = new Validator<Address>(new ValidationAttributeChecker<Address>());
var orderValidator = new Validator<Order>();

// Registering child validator
orderValidator.RegisterChildValidator(o => o.ShippingAddress, addressValidator);

var errors = orderValidator.ValidateObject(order);
// Errors for address will have keys like "ShippingAddress.City"
4. Integration with Pitasoft.Error

All validation results are returned as an ErrorCollection, allowing for easy aggregation and consistent error handling across your application.

public void ProcessUser(User user)
{
    var validator = CreateUserValidator();
    if (!validator.TryValidate(user, out var errors))
    {
        // Handle errors (e.g., return HTTP 400 with the collection)
        throw new ValidationException(errors);
    }
}

Fluent API Reference

String Methods
Method Description
NotNullOrEmpty(msg) Validates that the value is not null or empty
MinLength(min, msg) Minimum string length
MaxLength(max, msg) Maximum string length
Length(exact, msg) Exact string length
LengthBetween(min, max, msg) String length within a range
Matches(pattern, msg) Value matches a regular expression
Email(msg) Valid email address format
Null and Equality Methods
Method Description
NotNull(msg) Validates that the value is not null
Null(msg) Validates that the value is null
Equal(expected, msg) Value equals the expected value
NotEqual(unexpected, msg) Value does not equal the given value
Numeric / Comparable Methods
Method Description
Range(min, max, msg) Value is within the specified range (inclusive)
GreaterThan(min, msg) Value is strictly greater than the minimum
GreaterThanOrEqual(min, msg) Value is greater than or equal to the minimum
LessThan(max, msg) Value is strictly less than the maximum
LessThanOrEqual(max, msg) Value is less than or equal to the maximum
Collection Methods
Method Description
NotEmpty(msg) Collection is not empty
MinItems(min, msg) Collection has at least the specified number of elements
MaxItems(max, msg) Collection has at most the specified number of elements
Custom and Conditional Methods
Method Description
Must(predicate, msg) Custom rule with access to the full object instance
MustAsync(predicate, msg) Async custom rule
When(condition, configure) Apply rules only when the condition is true
Unless(condition, configure) Apply rules only when the condition is false
StopOnFirstFailure() Stop evaluating rules for this property after the first failure

All methods accept an optional code parameter to attach an error code for programmatic identification:

validator.For(u => u.Name).NotNullOrEmpty("Name is required", code: "NAME_REQUIRED");
Error Message Placeholders
Placeholder Value
{0} Visible property name (from DisplayAttribute if present)
{1} Current property value

Advanced Concepts

Reusable Validators with AbstractValidator<T>

Define validators as reusable classes by inheriting from AbstractValidator<T>:

public class UserValidator : AbstractValidator<User>
{
    protected override void Configure()
    {
        For(u => u.Name)
            .NotNullOrEmpty("Name is required")
            .MaxLength(50, "Name is too long");

        For(u => u.Age)
            .Range(18, 99, "Age must be between 18 and 99");
    }
}

// Usage
var validator = new UserValidator();
var errors = validator.ValidateObject(user);
Conditional Validation (When / Unless)

Apply rules only when a condition is met:

validator.For(u => u.CompanyName)
    .When(u => u.IsCompany, v => v.NotNullOrEmpty("Company name is required for companies"));

validator.For(u => u.PersonalId)
    .Unless(u => u.IsCompany, v => v.NotNullOrEmpty("Personal ID is required for individuals"));
Collection Validation (ForEach)

Validate each element of a collection individually with indexed error paths:

public class Order
{
    public List<OrderLine> Lines { get; set; }
}

var validator = new Validator<Order>();
validator.ForEach(o => o.Lines, line =>
{
    line.For(l => l.Quantity).GreaterThan(0, "Quantity must be greater than zero");
    line.For(l => l.ProductId).NotNullOrEmpty("Product is required");
});

var errors = validator.ValidateObject(order);
// Errors will have keys like "Lines[0].Quantity", "Lines[1].ProductId"
Asynchronous Validation

Use MustAsync for rules that require async operations (e.g., database lookups):

validator.For(u => u.Email)
    .MustAsync(async u => !await emailService.ExistsAsync(u.Email), "Email already in use");

var errors = await validator.ValidateObjectAsync(user);
Cross-property Validation

The Must method receives the full object instance, enabling validation that depends on multiple properties:

validator.For(u => u.YearsOfExperience)
    .Must(u => u.YearsOfExperience >= u.MinRequiredExperience, 
        "Years of experience for {0} must be at least the minimum required");
Stop on First Failure

Stop evaluating rules for a property after the first failure:

validator.For(u => u.Name)
    .StopOnFirstFailure()
    .NotNullOrEmpty("Name is required")
    .MaxLength(50, "Name is too long");
IChecker

Implement custom checkers to extend the validation engine. An IChecker can return structured errors with relative paths. This is useful for complex types or when you need to integrate with external validation libraries.

Performance

Validator<T> is designed for high performance:

  • Compiled expressions for fast property access.
  • Cached display name lookups (from DisplayAttribute).
  • Efficient rule grouping and property-based validation.

Español

Características

  • Múltiples estrategias de validación:
    • Data Annotations: Aprovecha los atributos de System.ComponentModel.DataAnnotations existentes.
    • API fluida: Define reglas con una sintaxis clara y legible con más de 25 métodos integrados.
    • Reglas personalizadas: Implementa lógica compleja mediante delegados o implementaciones propias de IChecker.
  • Validación jerárquica: Soporta validadores hijos para validar grafos de objetos anidados.
  • Validación de colecciones: Valida cada elemento de una colección con rutas de error indexadas (Items[0].Name).
  • Validación condicional: Aplica reglas solo cuando se cumple una condición (When / Unless).
  • Validación asíncrona: Soporte para reglas async mediante MustAsync y ValidateObjectAsync.
  • Detener al primer fallo: Opcionalmente detiene la evaluación de reglas de una propiedad tras el primer fallo.
  • Validadores reutilizables: Define validadores como clases reutilizables usando AbstractValidator<T>.
  • Códigos de error: Adjunta códigos de error opcionales a las reglas para identificación programática.
  • Alto rendimiento: Optimizado con compilación de expresiones y cachés para acceso a propiedades y nombres visibles.
  • Integración con Pitasoft.Error: Devuelve errores en el formato estándar ErrorCollection de la librería Pitasoft.Error.
  • Tipado fuerte: Soporta genéricos y expresiones lambda para evitar "magic strings".

Instalación

Agrega el paquete Pitasoft.Validation a tu proyecto:

dotnet add package Pitasoft.Validation

Nota: Depende de Pitasoft.Error.

Primeros pasos

1. Validación con Data Annotations

La forma más simple de empezar es usando los atributos ya presentes en tus modelos.

public class User
{
    [Required]
    [StringLength(50)]
    public string Name { get; set; }

    [Range(18, 99)]
    public int Age { get; set; }
}

// Uso con Métodos de Extensión (lo más fácil)
var user = new User { Name = "", Age = 10 };
ErrorCollection? errors = user.ValidateWithAttributes();

// O usando un validador manual
var validator = new Validator<User>(new ValidationAttributeChecker<User>());
errors = validator.ValidateObject(user);

if (errors?.Any() == true) 
{
    // Manejar errores
}
else
{
    // Válido
}
2. Reglas con API fluida

Define reglas programáticamente sin modificar tus clases de modelo.

// Uso con Métodos de Extensión
var errors = user.ValidateWithValidator(v => 
{
    v.For(u => u.Name)
        .NotNullOrEmpty("El nombre es obligatorio")
        .MinLength(2, "El nombre es demasiado corto")
        .MaxLength(50, "El nombre es demasiado largo")
        .Matches(@"^[a-zA-ZáéíóúÁÉÍÓÚñÑ\s]+$", "El nombre solo puede contener letras");

    v.For(u => u.Age)
        .Range(18, 99, "La edad debe estar entre 18 y 99");

    v.For(u => u.Email)
        .Email("Dirección de email no válida");
});

// O usando un validador manual
var validator = new Validator<User>();
validator.For(u => u.Name).NotNullOrEmpty("Obligatorio");
errors = validator.ValidateObject(user);
3. Objetos anidados (validadores hijos)

Valida grafos complejos registrando validadores para propiedades hijas.

public class Order
{
    public Address ShippingAddress { get; set; }
}

var addressValidator = new Validator<Address>(new ValidationAttributeChecker<Address>());
var orderValidator = new Validator<Order>();

// Registrando validador hijo
orderValidator.RegisterChildValidator(o => o.ShippingAddress, addressValidator);

var errors = orderValidator.ValidateObject(order);
// Los errores del address tendrán claves como "ShippingAddress.City"
4. Integración con Pitasoft.Error

Todos los resultados se devuelven como ErrorCollection, lo que permite una agregación sencilla y un manejo de errores consistente en tu aplicación.

public void ProcessUser(User user)
{
    var validator = CreateUserValidator();
    if (!validator.TryValidate(user, out var errors))
    {
        // Manejar errores (p.ej., devolver HTTP 400 con la colección)
        throw new ValidationException(errors);
    }
}

Referencia de la API fluida

Métodos para cadenas de texto
Método Descripción
NotNullOrEmpty(msg) Valida que el valor no sea nulo ni vacío
MinLength(min, msg) Longitud mínima de la cadena
MaxLength(max, msg) Longitud máxima de la cadena
Length(exact, msg) Longitud exacta de la cadena
LengthBetween(min, max, msg) Longitud de la cadena dentro de un rango
Matches(pattern, msg) El valor coincide con una expresión regular
Email(msg) Formato de dirección de email válido
Métodos de nulidad e igualdad
Método Descripción
NotNull(msg) Valida que el valor no sea nulo
Null(msg) Valida que el valor sea nulo
Equal(expected, msg) El valor es igual al esperado
NotEqual(unexpected, msg) El valor es distinto al indicado
Métodos numéricos / comparables
Método Descripción
Range(min, max, msg) El valor está dentro del rango especificado (inclusive)
GreaterThan(min, msg) El valor es estrictamente mayor que el mínimo
GreaterThanOrEqual(min, msg) El valor es mayor o igual que el mínimo
LessThan(max, msg) El valor es estrictamente menor que el máximo
LessThanOrEqual(max, msg) El valor es menor o igual que el máximo
Métodos para colecciones
Método Descripción
NotEmpty(msg) La colección no está vacía
MinItems(min, msg) La colección tiene al menos el número de elementos indicado
MaxItems(max, msg) La colección tiene como máximo el número de elementos indicado
Métodos personalizados y condicionales
Método Descripción
Must(predicate, msg) Regla personalizada con acceso a la instancia completa del objeto
MustAsync(predicate, msg) Regla personalizada asíncrona
When(condition, configure) Aplica reglas solo cuando la condición es verdadera
Unless(condition, configure) Aplica reglas solo cuando la condición es falsa
StopOnFirstFailure() Detiene la evaluación de reglas de esta propiedad tras el primer fallo

Todos los métodos aceptan un parámetro opcional code para adjuntar un código de error para identificación programática:

validator.For(u => u.Name).NotNullOrEmpty("El nombre es obligatorio", code: "NOMBRE_REQUERIDO");
Marcadores de posición en mensajes de error
Marcador Valor
{0} Nombre visible de la propiedad (desde DisplayAttribute si está presente)
{1} Valor actual de la propiedad

Conceptos avanzados

Validadores reutilizables con AbstractValidator<T>

Define validadores como clases reutilizables heredando de AbstractValidator<T>:

public class UserValidator : AbstractValidator<User>
{
    protected override void Configure()
    {
        For(u => u.Name)
            .NotNullOrEmpty("El nombre es obligatorio")
            .MaxLength(50, "El nombre es demasiado largo");

        For(u => u.Age)
            .Range(18, 99, "La edad debe estar entre 18 y 99");
    }
}

// Uso
var validator = new UserValidator();
var errors = validator.ValidateObject(user);
Validación condicional (When / Unless)

Aplica reglas solo cuando se cumple una condición:

validator.For(u => u.CompanyName)
    .When(u => u.IsCompany, v => v.NotNullOrEmpty("El nombre de empresa es obligatorio para empresas"));

validator.For(u => u.PersonalId)
    .Unless(u => u.IsCompany, v => v.NotNullOrEmpty("El DNI es obligatorio para personas físicas"));
Validación de colecciones (ForEach)

Valida cada elemento de una colección individualmente con rutas de error indexadas:

public class Order
{
    public List<OrderLine> Lines { get; set; }
}

var validator = new Validator<Order>();
validator.ForEach(o => o.Lines, line =>
{
    line.For(l => l.Quantity).GreaterThan(0, "La cantidad debe ser mayor que cero");
    line.For(l => l.ProductId).NotNullOrEmpty("El producto es obligatorio");
});

var errors = validator.ValidateObject(order);
// Los errores tendrán claves como "Lines[0].Quantity", "Lines[1].ProductId"
Validación asíncrona

Usa MustAsync para reglas que requieren operaciones asíncronas (p.ej., consultas a base de datos):

validator.For(u => u.Email)
    .MustAsync(async u => !await emailService.ExistsAsync(u.Email), "El email ya está en uso");

var errors = await validator.ValidateObjectAsync(user);
Validación cruzada entre propiedades

El método Must recibe la instancia completa del objeto, facilitando validaciones que dependan de múltiples campos:

validator.For(u => u.YearsOfExperience)
    .Must(u => u.YearsOfExperience >= u.MinRequiredExperience, 
        "Los años de experiencia para {0} deben ser al menos el mínimo requerido");
Detener al primer fallo

Detiene la evaluación de reglas de una propiedad tras el primer fallo:

validator.For(u => u.Name)
    .StopOnFirstFailure()
    .NotNullOrEmpty("El nombre es obligatorio")
    .MaxLength(50, "El nombre es demasiado largo");
IChecker

Implementa validadores propios (IChecker) para extender el motor de validación. Un IChecker puede devolver errores estructurados con rutas relativas, ideal para integraciones o tipos complejos.

Rendimiento

Validator<T> está diseñado para alto rendimiento:

  • Expresiones compiladas para un acceso rápido a propiedades.
  • Caché de nombres visibles (desde DisplayAttribute).
  • Agrupación eficiente de reglas y validación basada en propiedades.

Autor

Sebastián Martínez Pérez

Licencia

Copyright © 2020-2026 Pitasoft, S.L. Distribuido bajo la licencia LICENSE.txt incluida en este repositorio.

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 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 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 Pitasoft.Validation:

Package Downloads
Pitasoft.Validation.Rules

Implement rules to validate objects

Pitasoft.FluentValidation

Provides integration with FluentValidation for Pitasoft.Validation

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
5.1.3 45 3/5/2026
5.1.2 91 3/2/2026
5.1.1 85 3/2/2026
5.0.1 85 2/25/2026
4.3.0 470 11/20/2023
4.2.0 286 10/23/2023
4.1.0 750 11/18/2022
4.0.2 959 7/26/2022
4.0.0 815 7/26/2022
3.0.0 615 7/22/2022
2.0.0 657 6/26/2021