Abhay.MediatorCore
1.0.0
dotnet add package Abhay.MediatorCore --version 1.0.0
NuGet\Install-Package Abhay.MediatorCore -Version 1.0.0
<PackageReference Include="Abhay.MediatorCore" Version="1.0.0" />
<PackageVersion Include="Abhay.MediatorCore" Version="1.0.0" />
<PackageReference Include="Abhay.MediatorCore" />
paket add Abhay.MediatorCore --version 1.0.0
#r "nuget: Abhay.MediatorCore, 1.0.0"
#:package Abhay.MediatorCore@1.0.0
#addin nuget:?package=Abhay.MediatorCore&version=1.0.0
#tool nuget:?package=Abhay.MediatorCore&version=1.0.0
Abhay.MediatorCore
A lightweight, high-performance mediator library for .NET that implements the Mediator pattern with support for request/response, notifications, and pipeline behaviors.
๐ Features
- โ Request/Response Pattern - Send commands and queries with typed responses
- โ Notifications - Publish events to multiple handlers
- โ Pipeline Behaviors - Add cross-cutting concerns (logging, validation, caching)
- โ High Performance - Optimized with delegate caching and minimal reflection overhead
- โ Dependency Injection - First-class Microsoft.Extensions.DependencyInjection support
- โ Assembly Scanning - Automatic handler registration
- โ Lightweight - Minimal dependencies, focused API
- โ Multi-targeting - Supports .NET 10.0
๐ฆ Installation
dotnet add package Abhay.MediatorCore
Or via Package Manager Console:
Install-Package Abhay.MediatorCore
๐จ Quick Start
1. Define a Request and Handler
using MediatorCore;
// Request with response
public record GetUserQuery(int UserId) : IRequest<UserDto>;
// Handler
public class GetUserQueryHandler : IRequestHandler<GetUserQuery, UserDto>
{
private readonly IUserRepository _repository;
public GetUserQueryHandler(IUserRepository repository)
{
_repository = repository;
}
public async Task<UserDto> Handle(GetUserQuery request, CancellationToken cancellationToken)
{
var user = await _repository.GetByIdAsync(request.UserId, cancellationToken);
return new UserDto(user.Id, user.Name, user.Email);
}
}
2. Register MediatorCore
// In Program.cs or Startup.cs
builder.Services.AddMediator(typeof(Program).Assembly);
3. Use the Mediator
public class UserController : ControllerBase
{
private readonly IMediator _mediator;
public UserController(IMediator mediator) => _mediator = mediator;
[HttpGet("{id}")]
public async Task<IActionResult> GetUser(int id)
{
var user = await _mediator.Send(new GetUserQuery(id));
return Ok(user);
}
}
๐ข Notifications (Events)
Publish events to multiple handlers that run in parallel:
// Define notification
public record UserCreatedNotification(int UserId, string Email) : INotification;
// Multiple handlers - all will be executed
public class SendWelcomeEmailHandler : INotificationHandler<UserCreatedNotification>
{
private readonly IEmailService _emailService;
public SendWelcomeEmailHandler(IEmailService emailService)
{
_emailService = emailService;
}
public async Task Handle(UserCreatedNotification notification, CancellationToken ct)
{
await _emailService.SendWelcomeEmailAsync(notification.Email, ct);
}
}
public class CreateAuditLogHandler : INotificationHandler<UserCreatedNotification>
{
private readonly IAuditService _auditService;
public CreateAuditLogHandler(IAuditService auditService)
{
_auditService = auditService;
}
public async Task Handle(UserCreatedNotification notification, CancellationToken ct)
{
await _auditService.LogAsync($"User {notification.UserId} created", ct);
}
}
// Publish - all handlers execute in parallel
await _mediator.Publish(new UserCreatedNotification(userId, email));
๐ Pipeline Behaviors
Add cross-cutting concerns that wrap around your handlers:
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;
public LoggingBehavior(ILogger<LoggingBehavior<TRequest, TResponse>> logger)
{
_logger = logger;
}
public async Task<TResponse> Handle(
TRequest request,
CancellationToken cancellationToken,
RequestHandlerDelegate<TResponse> next)
{
var requestName = typeof(TRequest).Name;
_logger.LogInformation("Handling {RequestName}", requestName);
var stopwatch = Stopwatch.StartNew();
try
{
var response = await next();
stopwatch.Stop();
_logger.LogInformation(
"Handled {RequestName} in {ElapsedMs}ms",
requestName,
stopwatch.ElapsedMilliseconds);
return response;
}
catch (Exception ex)
{
stopwatch.Stop();
_logger.LogError(
ex,
"Error handling {RequestName} after {ElapsedMs}ms",
requestName,
stopwatch.ElapsedMilliseconds);
throw;
}
}
}
Validation Behavior Example
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
private readonly IEnumerable<IValidator<TRequest>> _validators;
public ValidationBehavior(IEnumerable<IValidator<TRequest>> validators)
{
_validators = validators;
}
public async Task<TResponse> Handle(
TRequest request,
CancellationToken cancellationToken,
RequestHandlerDelegate<TResponse> next)
{
if (_validators.Any())
{
var context = new ValidationContext<TRequest>(request);
var validationResults = await Task.WhenAll(
_validators.Select(v => v.ValidateAsync(context, cancellationToken)));
var failures = validationResults
.SelectMany(r => r.Errors)
.Where(f => f != null)
.ToList();
if (failures.Count != 0)
throw new ValidationException(failures);
}
return await next();
}
}
โ๏ธ Configuration
builder.Services.AddMediator(options =>
{
// Throw exception if no handler registered for a notification
options.ThrowIfNoNotificationHandlerRegistered = true;
}, typeof(Program).Assembly);
๐ฏ Manual Registration
If you prefer manual registration over assembly scanning:
// Register without assembly scanning
services.AddMediator();
// Manually register handlers
services.AddRequestHandler<GetUserQueryHandler, GetUserQuery, UserDto>();
services.AddNotificationHandler<SendEmailHandler, UserCreatedNotification>();
services.AddPipelineBehavior<LoggingBehavior<GetUserQuery, UserDto>, GetUserQuery, UserDto>();
๐ Commands Without Response
For commands that don't return a value, use Unit:
public record CreateUserCommand(string Name, string Email) : IRequest<Unit>;
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand, Unit>
{
public async Task<Unit> Handle(CreateUserCommand request, CancellationToken ct)
{
// Create user logic
await _repository.CreateAsync(request.Name, request.Email, ct);
return Unit.Value;
}
}
// Or implement IRequestHandler<CreateUserCommand> which returns Unit by default
public class CreateUserCommandHandler : IRequestHandler<CreateUserCommand>
{
public async Task<Unit> Handle(CreateUserCommand request, CancellationToken ct)
{
await _repository.CreateAsync(request.Name, request.Email, ct);
return Unit.Value;
}
}
๐งช Sample Projects
Check out the samples folder for complete working examples:
- Basic Request/Response - Simple command and query examples
- Notifications - Event publishing with multiple handlers
- Pipeline Behaviors - Logging, validation, and caching examples
- Real-world Scenarios - ASP.NET Core integration, CRUD operations
To run the samples:
cd samples/MediatorCore.Samples
dotnet run
๐ Performance
Abhay.MediatorCore is optimized for high performance:
- Delegate Caching - Handler invocations are cached to minimize reflection overhead
- Efficient Pipeline - Behaviors are chained efficiently without unnecessary allocations
- Concurrent Notifications - Multiple notification handlers execute in parallel
- Minimal Allocations - Uses modern C# patterns to reduce GC pressure
๐๏ธ Architecture Patterns
This library works great with:
- CQRS (Command Query Responsibility Segregation)
- Clean Architecture
- Domain-Driven Design (DDD)
- Vertical Slice Architecture
- Event-Driven Architecture
๐ง Requirements
- .NET 10.0
- Microsoft.Extensions.DependencyInjection.Abstractions 10.0.0+
๐ API Reference
Core Interfaces
// Send a request and get a response
public interface IMediator
{
Task<TResponse> Send<TResponse>(
IRequest<TResponse> request,
CancellationToken cancellationToken = default);
Task Publish<TNotification>(
TNotification notification,
CancellationToken cancellationToken = default)
where TNotification : INotification;
}
// Define a request
public interface IRequest<out TResponse> { }
// Define a request handler
public interface IRequestHandler<in TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken);
}
// Define a notification
public interface INotification { }
// Define a notification handler
public interface INotificationHandler<in TNotification>
where TNotification : INotification
{
Task Handle(TNotification notification, CancellationToken cancellationToken);
}
// Define a pipeline behavior
public interface IPipelineBehavior<in TRequest, TResponse>
{
Task<TResponse> Handle(
TRequest request,
CancellationToken cancellationToken,
RequestHandlerDelegate<TResponse> next);
}
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/AmazingFeature) - Commit your changes (
git commit -m 'Add some AmazingFeature') - Push to the branch (
git push origin feature/AmazingFeature) - Open a Pull Request
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ก Inspired By
This library is inspired by MediatR by Jimmy Bogard, reimagined with a focus on simplicity, performance, and modern .NET features.
๐ Acknowledgments
- Jimmy Bogard for the original MediatR pattern
- The .NET community for feedback and support
๐ Support
- GitHub Issues: Report bugs or request features
- Discussions: Ask questions and share ideas
โญ Show Your Support
If you find this library helpful, please give it a star on GitHub!
Made with โค๏ธ by Abhay
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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
- Microsoft.Extensions.DependencyInjection (>= 10.0.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 249 | 12/5/2025 |
Initial release with request/response pattern, notifications, and pipeline behaviors support.