Seamless MediatR integration for SimpleInjector with automatic configuration and convention-based registration
If you're using MediatR with SimpleInjector, this library eliminates all the boilerplate. It provides:
- One-line setup - Scan assemblies and auto-register all handlers, behaviors, and processors
- Smart defaults - Works out of the box with sensible conventions
- ASP.NET Core magic - Automatic
HttpContext.RequestAbortedtoken propagation to MediatR requests - Flexible configuration - Override anything when you need fine-grained control
- Full MediatR support - Handlers, notifications, streams, behaviors, pre/post processors, and exception handling
- .NET 10 ready - Updated to the latest .NET and MediatR versions
Install the package:
dotnet add package AdaskoTheBeAsT.MediatR.SimpleInjector.AspNetCoreRegister MediatR:
using AdaskoTheBeAsT.MediatR.SimpleInjector;
// In your Startup.cs or Program.cs
container.AddMediatRAspNetCore(typeof(Startup));That's it! All handlers in the assembly containing Startup are registered, and cancellation tokens from HTTP requests are automatically passed to MediatR.
Install the package:
dotnet add package AdaskoTheBeAsT.MediatR.SimpleInjectorRegister MediatR:
using AdaskoTheBeAsT.MediatR.SimpleInjector;
container.AddMediatR(typeof(MyHandler));By default, the library registers:
| Interface | Lifestyle |
|---|---|
IMediator |
Singleton |
IRequestHandler<TRequest, TResponse> |
Transient |
INotificationHandler<TNotification> |
Transient |
IStreamRequestHandler<TRequest, TResponse> |
Transient |
// By marker types
container.AddMediatR(typeof(MyHandler), typeof(AnotherHandler));
// By assembly instances
container.AddMediatR(assembly1, assembly2, assembly3);public static class MediatRConfigurator
{
private const string NamespacePrefix = "YourCompany.YourApp";
public static void Configure(Container container)
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(a => a.FullName.StartsWith(NamespacePrefix, StringComparison.OrdinalIgnoreCase))
.ToList();
container.AddMediatR(assemblies.ToArray());
}
}container.AddMediatRAspNetCore(
typeof(Startup), // Web project
typeof(CreateOrderHandler), // Application layer
typeof(SendEmailHandler) // Infrastructure layer
);container.AddMediatR(cfg =>
{
cfg.WithHandlerAssemblyMarkerTypes(typeof(MyHandler));
cfg.AsScoped(); // Default is Singleton
});container.AddMediatR(cfg =>
{
cfg.Using<MyCustomMediator>();
cfg.WithHandlerAssemblyMarkerTypes(typeof(MyHandler));
});var mockMediator = new Mock<IMediator>();
container.AddMediatR(cfg =>
{
cfg.Using(() => mockMediator.Object);
cfg.WithHandlerAssemblyMarkerTypes(typeof(MyHandler));
});Enable all built-in MediatR behaviors:
container.AddMediatR(cfg =>
{
cfg.WithHandlerAssemblyMarkerTypes(typeof(MyHandler));
cfg.UsingBuiltinPipelineProcessorBehaviors(true);
});This registers:
RequestPreProcessorBehavior<,>+ allIRequestPreProcessor<>implementationsRequestPostProcessorBehavior<,>+ allIRequestPostProcessor<,>implementationsRequestExceptionProcessorBehavior<,>+ allIRequestExceptionHandler<,,>implementationsRequestExceptionActionProcessorBehavior<,>+ allIRequestExceptionAction<,>implementations
Enable specific behaviors only:
container.AddMediatR(cfg =>
{
cfg.WithHandlerAssemblyMarkerTypes(typeof(MyHandler));
cfg.UsingBuiltinPipelineProcessorBehaviors(
requestPreProcessorBehaviorEnabled: true,
requestPostProcessorBehaviorEnabled: false,
requestExceptionProcessorBehaviorEnabled: true,
requestExceptionActionProcessorBehaviorEnabled: false);
});Add custom pipeline behaviors:
container.AddMediatR(cfg =>
{
cfg.WithHandlerAssemblyMarkerTypes(typeof(MyHandler));
cfg.UsingPipelineProcessorBehaviors(
typeof(LoggingBehavior<,>),
typeof(ValidationBehavior<,>),
typeof(TransactionBehavior<,>));
});Add custom stream pipeline behaviors:
container.AddMediatR(cfg =>
{
cfg.WithHandlerAssemblyMarkerTypes(typeof(MyHandler));
cfg.UsingStreamPipelineBehaviors(typeof(StreamLoggingBehavior<,>));
});Use ForeachAwait (default):
container.AddMediatR(cfg =>
{
cfg.WithHandlerAssemblyMarkerTypes(typeof(MyHandler));
cfg.WithNotificationPublisherForeachAwait();
});Use TaskWhenAll for parallel execution:
container.AddMediatR(cfg =>
{
cfg.WithHandlerAssemblyMarkerTypes(typeof(MyHandler));
cfg.WithNotificationPublisherTaskWhenAll();
});Use custom notification publisher:
container.AddMediatR(cfg =>
{
cfg.WithHandlerAssemblyMarkerTypes(typeof(MyHandler));
cfg.WithNotificationPublisherCustom<MyCustomPublisher>();
});Control exactly which pre/post processors and exception handlers get registered:
container.AddMediatR(cfg =>
{
cfg.WithHandlerAssemblyMarkerTypes(typeof(MyHandler));
cfg.UsingBuiltinPipelineProcessorBehaviors(
requestPreProcessorBehaviorEnabled: true,
requestPostProcessorBehaviorEnabled: true,
requestExceptionProcessorBehaviorEnabled: true,
requestExceptionActionProcessorBehaviorEnabled: true);
// Register specific processors in order
cfg.WithRequestPreProcessorTypes(
typeof(LoggingPreProcessor<>),
typeof(ValidationPreProcessor<>));
cfg.WithRequestPostProcessorTypes(
typeof(CacheInvalidationPostProcessor<,>),
typeof(NotificationPostProcessor<,>));
cfg.WithRequestExceptionProcessorTypes(
typeof(LoggingExceptionProcessor<,,>),
typeof(RetryExceptionProcessor<,,>));
cfg.WithRequestExceptionActionProcessorTypes(
typeof(AlertingExceptionAction<,>));
});| Package | NuGet |
|---|---|
| AdaskoTheBeAsT.MediatR.SimpleInjector | |
| AdaskoTheBeAsT.MediatR.SimpleInjector.AspNetCore | |
| AdaskoTheBeAsT.MediatR.SimpleInjector.AspNet |
- .NET Standard 2.0+ - Works with .NET Framework 4.6.1+, .NET Core 2.0+, .NET 5+
- MediatR 13.1.0+ - Latest MediatR version
- SimpleInjector 5.5.0+ - Latest SimpleInjector version
dotnet testThe test suite needs a MediatR license key. MediatR resolves it from the environment
(MEDIATR_LICENSE_KEY, then the shared LUCKYPENNY_LICENSE_KEY) unless a key is passed explicitly
via WithLicenseKey(...). In CI the value comes from the MEDIATR_LICENSE_KEY GitHub secret
(see .github/workflows/ci.yml).
To supply it locally, copy the template and fill in your key:
cp .env.example .envMEDIATR_LICENSE_KEY=your-license-key.env is git ignored, so the key never lands in the repository. A module initializer in the test
projects (test/TestEnvironment.cs, linked into every test project) uses
dotenv.net to probe upwards from the test output
directory for the nearest .env and exports every KEY=VALUE entry into the test process before
the first mediator is resolved. Variables that are already set in the environment are never
overwritten, so CI values always win over the file.
This works the same for dotnet test and for the test runners in Visual Studio, Rider, and VS Code.
If you prefer not to keep a file in the working tree, set a user-level environment variable instead
(setx MEDIATR_LICENSE_KEY "your-license-key" on Windows) and restart your IDE or shell.
Because the test projects also target .NET Framework (net462 - net481), the suite has to be run on Windows.
Contributions are welcome! Please feel free to submit issues or pull requests.
This project is licensed under the MIT License - see the LICENSE file for details.
Special thanks to:
- Jimmy Bogard - For creating MediatR
- Steven van Deursen - For creating SimpleInjector
- Sebastian Kleinschmager - For the automatic RequestAborted token passing idea
- Konrad Rudolph - For the IsAssignableToGenericType implementation
This library was inspired by MediatR.Extensions.Microsoft.DependencyInjection and adapted for SimpleInjector's unique capabilities.
⭐ Star this repo if you find it useful!
Made with ❤️ by Adam "AdaskoTheBeAsT" Pluciński