High-performance Mediator pattern implementation for .NET with CQRS support. Inspired by MediatR with focus on performance and simplicity.
- π High Performance - Static caching, minimal allocations, aggressive inlining
- π¦ CQRS Ready - Request/Response, Commands, Queries, and Notifications
- π Pipeline Behaviors - Cross-cutting concerns (logging, validation, caching)
- β‘ Streaming Support -
IAsyncEnumerablefor large datasets - π‘οΈ Validation - Built-in validation behavior with custom validators
- π― Pre/Post Processors - Execute logic before/after handlers
- π DI Integration - Native Microsoft.Extensions.DependencyInjection support
dotnet add package Mediator
dotnet add package Mediator.Extensions.DependencyInjection// Request
public record GetUserQuery(int UserId) : IRequest<UserDto>;
// Handler
public class GetUserHandler : IRequestHandler<GetUserQuery, UserDto>
{
public async Task<UserDto> Handle(GetUserQuery request, CancellationToken ct)
{
return new UserDto(request.UserId, "John Doe");
}
}services.AddMediator(config =>
{
config.AddAssembly(typeof(Program).Assembly);
});public class UserController
{
private readonly IMediator _mediator;
public UserController(IMediator mediator) => _mediator = mediator;
public async Task<UserDto> GetUser(int id)
{
return await _mediator.Send(new GetUserQuery(id));
}
}public record CreateUserCommand(string Name, string Email) : IRequest;
public class CreateUserHandler : IRequestHandler<CreateUserCommand, Unit>
{
public async Task<Unit> Handle(CreateUserCommand request, CancellationToken ct)
{
// Create user logic
return Unit.Value;
}
}public record UserCreated(int UserId, string Name) : INotification;
public class SendWelcomeEmail : INotificationHandler<UserCreated>
{
public async Task Handle(UserCreated notification, CancellationToken ct)
{
// Send email
}
}
public class LogUserCreated : INotificationHandler<UserCreated>
{
public async Task Handle(UserCreated notification, CancellationToken ct)
{
// Log event
}
}
// Usage
await _mediator.Publish(new UserCreated(1, "John"));public record GetLogsStream(DateTime From) : IStreamRequest<LogEntry>;
public class GetLogsHandler : IStreamRequestHandler<GetLogsStream, LogEntry>
{
public async IAsyncEnumerable<LogEntry> Handle(
GetLogsStream request,
[EnumeratorCancellation] CancellationToken ct)
{
await foreach (var log in _db.GetLogsAsync(request.From, ct))
{
yield return log;
}
}
}public class LoggingBehavior<TRequest, TResponse>
: IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
public async Task<TResponse> Handle(
TRequest request,
RequestHandlerDelegate<TResponse> next,
CancellationToken ct)
{
_logger.LogInformation("Handling {Request}", typeof(TRequest).Name);
var response = await next();
_logger.LogInformation("Handled {Request}", typeof(TRequest).Name);
return response;
}
}
// Registration
services.AddMediator(config =>
{
config.AddAssembly(typeof(Program).Assembly);
config.AddBehavior(typeof(LoggingBehavior<,>));
});public class CreateUserValidator : IValidator<CreateUserCommand>
{
public Task<ValidationResult> ValidateAsync(
CreateUserCommand request,
CancellationToken ct)
{
if (string.IsNullOrEmpty(request.Name))
return Task.FromResult(
ValidationResult.Failure("Name", "Name is required"));
return Task.FromResult(ValidationResult.Success);
}
}
// Registration
services.AddMediator(config =>
{
config.AddAssembly(typeof(Program).Assembly);
config.AddBehavior(typeof(ValidationBehavior<,>));
});
services.AddTransient<IValidator<CreateUserCommand>, CreateUserValidator>();services.AddMediator(config =>
{
// Scan assemblies for handlers
config.AddAssembly(typeof(Program).Assembly);
// Configure lifetimes
config.MediatorLifetime = ServiceLifetime.Scoped;
config.HandlerLifetime = ServiceLifetime.Transient;
config.BehaviorLifetime = ServiceLifetime.Transient;
// Add behaviors (executed in order)
config.AddBehavior(typeof(LoggingBehavior<,>));
config.AddBehavior(typeof(ValidationBehavior<,>));
config.AddBehavior(typeof(RequestPreProcessorBehavior<,>));
config.AddBehavior(typeof(RequestPostProcessorBehavior<,>));
});The library includes 79 comprehensive unit tests covering:
- β Request/Response handling
- β Notifications (multiple handlers)
- β Pipeline behaviors
- β Pre/Post processors
- β Validation
- β Streaming with IAsyncEnumerable
- β Cancellation support
- β Exception handling
cd tests/Mediator.Tests
dotnet testMediator/
βββ src/
β βββ Mediator/
β β βββ Abstractions/ # Interfaces
β β βββ Behaviors/ # Pipeline behaviors
β β βββ Exceptions/ # Custom exceptions
β β βββ Validation/ # Validation support
β β βββ Wrappers/ # Handler wrappers
β β βββ Mediator.cs # Main implementation
β β βββ Unit.cs # Unit type for void returns
β βββ Mediator.Extensions.DependencyInjection/
β βββ MediatorServiceConfiguration.cs
β βββ ServiceCollectionExtensions.cs
βββ tests/
βββ Mediator.Tests/ # Unit tests
Contributions are welcome! Please feel free to submit a Pull Request.
This project is licensed under the MIT License.