Skip to content

AdaskoTheBeAsT/AdaskoTheBeAsT.FluentValidation.SimpleInjector

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

105 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AdaskoTheBeAsT.FluentValidation.SimpleInjector

Seamlessly integrate FluentValidation with SimpleInjector - automatic validator registration made simple.

CodeFactor Build Status Azure DevOps tests Azure DevOps coverage Quality Gate Status Nuget Nuget


Why Use This?

Stop manually registering validators one by one. This library automatically scans your assemblies and registers all IValidator<T> implementations with SimpleInjector, saving you time and reducing boilerplate code.

Key Features

  • Zero Configuration - Works out of the box with sensible defaults
  • Flexible Scanning - Register validators by assembly, marker types, or custom configuration
  • Lifecycle Control - Choose between Singleton, Scoped, or Transient lifestyles
  • Smart Registration - Supports both single validator and collection patterns
  • Selective Registration - Skip specific validators with [SkipValidatorRegistration] attribute
  • Multi-Target Support - Compatible with .NET 8.0, 9.0, and 10.0

Installation

dotnet add package AdaskoTheBeAsT.FluentValidation.SimpleInjector

Quick Start

Basic Usage

The simplest way to register all validators from an assembly:

using SimpleInjector;
using AdaskoTheBeAsT.FluentValidation.SimpleInjector;

var container = new Container();

// Register all validators from the assembly containing PersonValidator
container.AddFluentValidation(typeof(PersonValidator));

That's it! All validators in that assembly are now registered and ready to use.

Resolve and Use

var validator = container.GetInstance<IValidator<Person>>();
var result = validator.Validate(new Person { Name = "John" });

Usage Patterns

1. Register by Marker Types

Use types as markers to identify which assemblies to scan:

// Single assembly
container.AddFluentValidation(typeof(PersonValidator));

// Multiple assemblies
container.AddFluentValidation(
    typeof(PersonValidator),
    typeof(OrderValidator),
    typeof(ProductValidator)
);

2. Register by Assemblies

Directly specify assemblies to scan:

var assembly = typeof(PersonValidator).Assembly;
container.AddFluentValidation(assembly);

// Or multiple assemblies
var assemblies = new[] 
{ 
    typeof(PersonValidator).Assembly,
    typeof(OrderValidator).Assembly 
};
container.AddFluentValidation(assemblies);

3. Scan Solution Assemblies

Automatically discover and register validators from all assemblies in your solution:

public static class ValidatorConfig
{
    public static void RegisterValidators(Container container)
    {
        var assemblies = AppDomain.CurrentDomain
            .GetAssemblies()
            .Where(a => a.FullName.StartsWith("YourCompany."))
            .ToList();

        container.AddFluentValidation(assemblies);
    }
}

Advanced Configuration

Lifecycle Management

Choose how validators are instantiated and cached:

// Singleton (default) - one instance shared across the application
container.AddFluentValidation(cfg => 
{
    cfg.WithAssembliesToScan(assemblies);
    cfg.AsSingleton();
});

// Scoped - one instance per scope/request
container.AddFluentValidation(cfg => 
{
    cfg.WithAssembliesToScan(assemblies);
    cfg.AsScoped();
});

// Transient - new instance every time
container.AddFluentValidation(cfg => 
{
    cfg.WithAssembliesToScan(assemblies);
    cfg.AsTransient();
});

Registration Patterns

Single Validator Pattern (Default)

Registers one validator per type. Use this when you have one validator per model:

container.AddFluentValidation(cfg =>
{
    cfg.WithAssembliesToScan(assemblies);
    cfg.RegisterAsSingleValidator(); // Default
});

// Resolves to a single IValidator<Person>
var validator = container.GetInstance<IValidator<Person>>();

Validator Collection Pattern

Register multiple validators for the same type:

container.AddFluentValidation(cfg =>
{
    cfg.WithAssembliesToScan(assemblies);
    cfg.RegisterAsValidatorCollection();
});

// Resolves to multiple validators
var validators = container.GetAllInstances<IValidator<Person>>();

Selective Registration

Skip specific validators from auto-registration:

using AdaskoTheBeAsT.FluentValidation.SimpleInjector;

// This validator will be excluded from registration
[SkipValidatorRegistration]
public class PersonInternalValidator : AbstractValidator<Person>
{
    public PersonInternalValidator()
    {
        RuleFor(x => x.Name).NotEmpty();
    }
}

Use Case: When building composite validators using included rules:

public class PersonValidator : AbstractValidator<Person>
{
    public PersonValidator()
    {
        Include(new PersonInternalValidator());
        Include(new PersonExternalValidator());
    }
}

// Mark the included validators to prevent duplicate registration
[SkipValidatorRegistration]
public class PersonInternalValidator : AbstractValidator<Person> { ... }

[SkipValidatorRegistration]
public class PersonExternalValidator : AbstractValidator<Person> { ... }

Complete Configuration Example

using SimpleInjector;
using AdaskoTheBeAsT.FluentValidation.SimpleInjector;

public class Startup
{
    public void ConfigureServices()
    {
        var container = new Container();

        // Advanced configuration
        container.AddFluentValidation(cfg =>
        {
            // Specify assemblies to scan
            cfg.WithAssembliesToScan(
                typeof(PersonValidator).Assembly,
                typeof(OrderValidator).Assembly
            );

            // Set validator lifecycle
            cfg.AsScoped();

            // Use single validator pattern
            cfg.RegisterAsSingleValidator();
        });

        // Verify container configuration
        container.Verify();
    }
}

Real-World Examples

ASP.NET Core Integration

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // Add SimpleInjector
        builder.Services.AddSimpleInjector(container =>
        {
            // Register validators with scoped lifetime
            container.AddFluentValidation(cfg =>
            {
                cfg.WithAssembliesToScan(typeof(Program).Assembly);
                cfg.AsScoped();
            });
        });

        var app = builder.Build();
        app.Run();
    }
}

MediatR Pipeline Integration

// Validation pipeline behavior
public class ValidationBehavior<TRequest, TResponse> 
    : IPipelineBehavior<TRequest, TResponse>
    where TRequest : IRequest<TResponse>
{
    private readonly IValidator<TRequest> _validator;

    public ValidationBehavior(IValidator<TRequest> validator)
    {
        _validator = validator;
    }

    public async Task<TResponse> Handle(
        TRequest request, 
        RequestHandlerDelegate<TResponse> next, 
        CancellationToken cancellationToken)
    {
        var validationResult = await _validator.ValidateAsync(request, cancellationToken);
        
        if (!validationResult.IsValid)
        {
            throw new ValidationException(validationResult.Errors);
        }

        return await next();
    }
}

Framework Support

.NET Version Support
.NET 10.0
.NET 9.0
.NET 8.0

Dependencies


Contributing

Contributions are welcome! Please feel free to submit a Pull Request.


License

This project is licensed under the MIT License - see the LICENSE file for details.


Author

Adam "AdaskoTheBeAsT" Pluciński

If this library saved you time, consider giving it a ⭐ on GitHub!

About

FluentValidation extensions to SimpleInjector

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages