Abhay.MediatorCore 1.0.0

dotnet add package Abhay.MediatorCore --version 1.0.0
                    
NuGet\Install-Package Abhay.MediatorCore -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Abhay.MediatorCore" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Abhay.MediatorCore" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Abhay.MediatorCore" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Abhay.MediatorCore --version 1.0.0
                    
#r "nuget: Abhay.MediatorCore, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Abhay.MediatorCore@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Abhay.MediatorCore&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Abhay.MediatorCore&version=1.0.0
                    
Install as a Cake Tool

Abhay.MediatorCore

NuGet NuGet Downloads License: MIT

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.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/AmazingFeature)
  3. Commit your changes (git commit -m 'Add some AmazingFeature')
  4. Push to the branch (git push origin feature/AmazingFeature)
  5. 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

โญ Show Your Support

If you find this library helpful, please give it a star on GitHub!


Made with โค๏ธ by Abhay

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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.