Seamlessly integrate FluentValidation with SimpleInjector - automatic validator registration made simple.
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.
- 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
dotnet add package AdaskoTheBeAsT.FluentValidation.SimpleInjectorThe 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.
var validator = container.GetInstance<IValidator<Person>>();
var result = validator.Validate(new Person { Name = "John" });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)
);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);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);
}
}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();
});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>>();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>>();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> { ... }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();
}
}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();
}
}// 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();
}
}| .NET Version | Support |
|---|---|
| .NET 10.0 | ✅ |
| .NET 9.0 | ✅ |
| .NET 8.0 | ✅ |
- FluentValidation >= 12.1.0
- SimpleInjector >= 5.5.0
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License - see the LICENSE file for details.
Adam "AdaskoTheBeAsT" Pluciński
If this library saved you time, consider giving it a ⭐ on GitHub!