SebastianGuzmanMorla.Validator
1.0.3
dotnet add package SebastianGuzmanMorla.Validator --version 1.0.3
NuGet\Install-Package SebastianGuzmanMorla.Validator -Version 1.0.3
<PackageReference Include="SebastianGuzmanMorla.Validator" Version="1.0.3" />
<PackageVersion Include="SebastianGuzmanMorla.Validator" Version="1.0.3" />
<PackageReference Include="SebastianGuzmanMorla.Validator" />
paket add SebastianGuzmanMorla.Validator --version 1.0.3
#r "nuget: SebastianGuzmanMorla.Validator, 1.0.3"
#:package SebastianGuzmanMorla.Validator@1.0.3
#addin nuget:?package=SebastianGuzmanMorla.Validator&version=1.0.3
#tool nuget:?package=SebastianGuzmanMorla.Validator&version=1.0.3
SebastianGuzmanMorla.Validator
A strongly-typed validation library for .NET that allows you to easily build entity validators with support for custom validation rules, conditional logic, nested entity mapping, and automated dependency injection registration using a Roslyn Source Generator.
Features
- Strongly-typed validation: Write distinct validators specific to each entity model.
- Fluent Property Rules: Chain validation rules on individual properties cleanly.
- Conditional Validation: Run validation rules only when dynamic conditions are satisfied.
- Interface Cascading: Automatically execute and weave validation rules across implemented interfaces.
- Source Generator: Automates validator registration in Microsoft.Extensions.DependencyInjection.
- Flexible Control Flow: Configure rule chains to continue or stop validation upon failure.
Installation
Install the NuGet package:
dotnet add package SebastianGuzmanMorla.Validator
Basic Usage
1. Create a model
First, define the entity model you want to validate:
public class User
{
public string? Name { get; set; }
public string? Email { get; set; }
public int? Age { get; set; }
}
2. Implement the Validator
Create a validator class inheriting from Validator<TEntity> and define rules inside the constructor:
using SebastianGuzmanMorla.Validator;
public class UserValidator : Validator<User>
{
public UserValidator()
{
RuleFor(u => u.Name)
.NotNull((_, _) => "Name cannot be null")
.NotEmpty((_, _) => "Name is required");
RuleFor(u => u.Email)
.NotNull((_, _) => "Email cannot be null")
.NotEmpty((_, _) => "Email is required")
.EmailAddress((_, _) => "Email must be a valid address");
RuleFor(u => u.Age)
.NotNull((_, _) => "Age cannot be null")
.Minimum(1, (_, _) => "Age must be greater than 0");
}
}
3. Service Configuration (Dependency Injection)
The Roslyn Source Generator automatically generates the registration logic inside a partial ConfigureServices class:
public partial class ConfigureServices
{
private static partial void RegisterValidators(IServiceCollection services);
public static IServiceCollection ConfigureDomain(this IServiceCollection services)
{
// Automatically registers all validators in the assembly as Singletons
RegisterValidators(services);
return services;
}
}
4. Execute the Validator
Inject IValidator<T> into your services or Minimal API endpoints to run validations:
WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Services.ConfigureDomain();
WebApplication app = builder.Build();
app.MapPost("/users", async (User user, [FromServices] IServiceProvider serviceProvider, [FromServices] IValidator<User> validator) =>
{
var result = await validator.Validate(user, serviceProvider);
if (!result.IsValid)
{
return Results.BadRequest(new
{
Errors = result.Errors
});
}
return Results.Created($"/users/{user.Id}", user);
});
app.Run();
Advanced Examples
Interface Validation Cascading
You can validate shared attributes by defining rules on interfaces. The Source Generator automatically weaves these rules into any concrete classes that implement the interface.
Define your validation interface inheriting from IEntityValidation:
public interface IDeviceIdValidation : IEntityValidation
{
public Guid DeviceId { get; set; }
}
Create a validator for the interface:
public class DeviceIdValidator : Validator<IDeviceIdValidation>
{
public DeviceIdValidator()
{
RuleFor(x => x.DeviceId)
.NotEmpty((_, _) => "Device ID cannot be empty");
}
}
Implement the interface on a concrete entity class (declared as partial) and define the class validator:
public class Device : IDeviceIdValidation
{
public Guid DeviceId { get; set; }
public string? Name { get; set; }
}
public partial class DeviceValidator : Validator<Device>
{
public DeviceValidator()
{
RuleFor(d => d.Name)
.NotEmpty((_, _) => "Device name is required");
}
}
The Source Generator will automatically weave the validations behind the scenes:
// Automatically generated by the Source Generator:
public partial class DeviceValidator
{
protected override ImmutableArray<Func<IServiceProvider, Device, CancellationToken, Task<ValidationResult>>> InterfaceValidations =>
[
(serviceProvider, entity, cancellationToken) =>
serviceProvider.GetRequiredService<IValidator<IDeviceIdValidation>>().Validate(entity, serviceProvider, cancellationToken)
];
}
Conditional Validation (RuleForWhen)
To conditionally run rules based on a dynamic runtime check, use RuleForWhen instead of RuleFor:
public class UserValidator : Validator<User>
{
public UserValidator()
{
RuleForWhen(u => u.PromoCode, (serviceProvider, user, cancellationToken) =>
Task.FromResult(user.HasOptedInForPromo)
)
.NotEmpty((_, _) => "Promo code is required when promotional offers are enabled");
}
}
Nested Entities and Collections (ValidateEntity)
Validate nested objects or collections of entities recursively. The library will resolve the appropriate validators from DI and append deep paths to error keys (e.g., Headquarters.Street or Employees[0].Name):
public class Company
{
public Address Headquarters { get; set; }
public List<Employee> Employees { get; set; }
}
public class CompanyValidator : Validator<Company>
{
public CompanyValidator()
{
// Validates Headquarters using IValidator<Address>
ValidateEntity(c => c.Headquarters);
// Validates each item in the collection using IValidator<Employee>
ValidateEntity(c => c.Employees);
}
}
API Reference
Validator Methods
RuleFor(propertyExpression): Sets up validation rules on a property.RuleForWhen(propertyExpression, asyncPredicate): Sets up conditional validation rules.ValidateEntity(propertyExpression): Configures nested entity or collection validation.
Validation Rules (ValidationPropertyRules)
All rules accept an optional ValidationErrorHandle parameter at the end of the method chain to control execution flow (Continue, StopProperty, or StopAll).
NotNull(messageFunc): Asserts property is not null.NotEmpty(messageFunc): Asserts string is not empty/whitespace, collection has elements, or Guid is notGuid.Empty.EmailAddress(messageFunc): Validates email format.Equal(value, messageFunc): Asserts property value equals a constant.Equal(propertyExpression, messageFunc): Asserts property value equals another property on the same entity.NotEqual(value, messageFunc): Asserts property value does not equal a constant.NotEqual(propertyExpression, messageFunc): Asserts property value does not equal another property.Minimum(value, messageFunc): Asserts value is>= value.Maximum(value, messageFunc): Asserts value is<= value.MinimumLength(length, messageFunc): Asserts string length is>= length.MaximumLength(length, messageFunc): Asserts string length is<= length.Between(min, max, messageFunc): Asserts value is in inclusive range[min, max].Matches(regex, messageFunc): Asserts string matches regex pattern.Must(predicate, messageFunc): Asynchronous predicate returningTask<bool>with a predefined message.Must(dynamicPredicate): Asynchronous predicate returningTask<(bool IsValid, string? ErrorMessage)>with dynamic error details returned from execution.
Validation Result
ValidationResult exposes:
IsValid: Boolean indicating validation success.Errors: Dictionary where key is the property path and value is a list of error strings.
Requirements
- .NET 10.0 or higher
- Microsoft.Extensions.DependencyInjection
License
This project is licensed under the MIT License - see the LICENSE file for details.
| Product | Versions 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. |
-
net10.0
-
net8.0
-
net9.0
NuGet packages (2)
Showing the top 2 NuGet packages that depend on SebastianGuzmanMorla.Validator:
| Package | Downloads |
|---|---|
|
SebastianGuzmanMorla.DDD.Domain
Biblioteca de dominio que define entidades base, mensajes y atributos para la implementación de Domain-Driven Design (DDD) en .NET 10.0+. |
|
|
SebastianGuzmanMorla.DDD
Biblioteca base para la implementación de Domain-Driven Design (DDD) en .NET 10.0+ con soporte para repositorios EF Core, Unit of Work y Source Generators. |
GitHub repositories
This package is not used by any popular GitHub repositories.