Alvi.Mediator 1.0.1

dotnet add package Alvi.Mediator --version 1.0.1
                    
NuGet\Install-Package Alvi.Mediator -Version 1.0.1
                    
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="Alvi.Mediator" Version="1.0.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Alvi.Mediator" Version="1.0.1" />
                    
Directory.Packages.props
<PackageReference Include="Alvi.Mediator" />
                    
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 Alvi.Mediator --version 1.0.1
                    
#r "nuget: Alvi.Mediator, 1.0.1"
                    
#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 Alvi.Mediator@1.0.1
                    
#: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=Alvi.Mediator&version=1.0.1
                    
Install as a Cake Addin
#tool nuget:?package=Alvi.Mediator&version=1.0.1
                    
Install as a Cake Tool

Alvi.Mediator

A lightweight, high-performance CQRS mediator pattern implementation for .NET applications. Supports commands, queries, notifications, and pipeline behaviors.

NuGet Version NuGet Downloads

Features

  • 🚀 High Performance: Minimal overhead with efficient handler resolution
  • 📦 Lightweight: Small footprint with minimal dependencies
  • 🔧 Easy to Use: Simple API with fluent registration
  • 🏗️ CQRS Support: Clear separation between Commands and Queries
  • 📬 Notifications: Publish/subscribe pattern for domain events
  • 🔀 Pipeline Behaviors: Cross-cutting concerns like logging, validation, caching
  • 🎯 Dependency Injection: Full integration with Microsoft.Extensions.DependencyInjection
  • 📖 Well Documented: Comprehensive XML documentation

Installation

Install via NuGet Package Manager:

dotnet add package Alvi.Mediator

Or via Package Manager Console:

Install-Package Alvi.Mediator

Quick Start

1. Register the Mediator

using Alvi.Mediator;

var builder = WebApplication.CreateBuilder(args);

// Register mediator and scan current assembly for handlers
builder.Services.AddAlviMediator();

// Or scan specific assemblies
builder.Services.AddAlviMediator(typeof(GetUserQuery).Assembly);

var app = builder.Build();

2. Create Commands and Handlers

using Alvi.Mediator;

// Command with result
public record CreateUserCommand(string Name, string Email) : ICommand<CreateUserResult>;

public record CreateUserResult(int UserId, string Name);

public class CreateUserHandler : ICommandHandler<CreateUserCommand, CreateUserResult>
{
    public async Task<CreateUserResult> HandleAsync(CreateUserCommand command, CancellationToken cancellationToken = default)
    {
        // Your business logic here
        var userId = await CreateUserInDatabase(command.Name, command.Email);
        return new CreateUserResult(userId, command.Name);
    }
}

// Command without result
public record DeleteUserCommand(int UserId) : ICommand;

public class DeleteUserHandler : ICommandHandler<DeleteUserCommand>
{
    public async Task HandleAsync(DeleteUserCommand command, CancellationToken cancellationToken = default)
    {
        // Your business logic here
        await DeleteUserFromDatabase(command.UserId);
    }
}

3. Create Queries and Handlers

using Alvi.Mediator;

public record GetUserQuery(int UserId) : IQuery<UserDto>;

public record UserDto(int Id, string Name, string Email);

public class GetUserHandler : IQueryHandler<GetUserQuery, UserDto>
{
    public async Task<UserDto> HandleAsync(GetUserQuery query, CancellationToken cancellationToken = default)
    {
        // Your data access logic here
        var user = await GetUserFromDatabase(query.UserId);
        return new UserDto(user.Id, user.Name, user.Email);
    }
}

4. Create Notifications and Handlers

using Alvi.Mediator;

public record UserCreatedNotification(int UserId, string Name, string Email) : INotification;

public class EmailNotificationHandler : INotificationHandler<UserCreatedNotification>
{
    public async Task HandleAsync(UserCreatedNotification notification, CancellationToken cancellationToken = default)
    {
        // Send welcome email
        await SendWelcomeEmail(notification.Email);
    }
}

public class AuditLogHandler : INotificationHandler<UserCreatedNotification>
{
    public async Task HandleAsync(UserCreatedNotification notification, CancellationToken cancellationToken = default)
    {
        // Log user creation
        await LogUserCreation(notification.UserId);
    }
}

5. Use the Mediator

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IMediator _mediator;

    public UsersController(IMediator mediator)
    {
        _mediator = mediator;
    }

    [HttpPost]
    public async Task<IActionResult> CreateUser(CreateUserCommand command)
    {
        var result = await _mediator.SendAsync(command);
        return Ok(result);
    }

    [HttpGet("{id}")]
    public async Task<IActionResult> GetUser(int id)
    {
        var user = await _mediator.QueryAsync(new GetUserQuery(id));
        return Ok(user);
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteUser(int id)
    {
        await _mediator.SendAsync(new DeleteUserCommand(id));
        return NoContent();
    }
}

Pipeline Behaviors

Pipeline behaviors allow you to implement cross-cutting concerns like logging, validation, caching, etc.

Built-in Behaviors

Logging Behavior
using Alvi.Mediator.Behaviors;

// Register the logging behavior
builder.Services.AddPipelineBehavior<LoggingBehavior<ICommand<object>, object>>();
Performance Behavior
using Alvi.Mediator.Behaviors;

// Register performance monitoring (default threshold: 5000ms)
builder.Services.AddPipelineBehavior<PerformanceBehavior<ICommand<object>, object>>();

// Or with custom threshold
builder.Services.AddSingleton(_ => new PerformanceBehavior<ICommand<object>, object>(2000));
builder.Services.AddPipelineBehavior<PerformanceBehavior<ICommand<object>, object>>();

Custom Pipeline Behaviors

public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
    where TRequest : ICommand<TResponse>
{
    private readonly IValidator<TRequest> _validator;

    public ValidationBehavior(IValidator<TRequest> validator)
    {
        _validator = validator;
    }

    public async Task<TResponse> HandleAsync(TRequest request, Func<Task<TResponse>> next, CancellationToken cancellationToken = default)
    {
        // Validate the request
        var validationResult = await _validator.ValidateAsync(request, cancellationToken);
        
        if (!validationResult.IsValid)
        {
            throw new ValidationException(validationResult.Errors);
        }

        // Continue to next behavior/handler
        return await next();
    }
}

// Register the behavior
builder.Services.AddPipelineBehavior<ValidationBehavior<CreateUserCommand, CreateUserResult>>();

Advanced Registration

Manual Handler Registration

// Register specific handlers manually
builder.Services.AddCommandHandler<CreateUserCommand, CreateUserResult, CreateUserHandler>();
builder.Services.AddQueryHandler<GetUserQuery, UserDto, GetUserHandler>();
builder.Services.AddNotificationHandler<UserCreatedNotification, EmailNotificationHandler>();

Service Lifetimes

// Register with specific lifetimes
builder.Services.AddAlviMediator(ServiceLifetime.Scoped, typeof(MyHandler).Assembly);

// Or for individual handlers
builder.Services.AddCommandHandler<MyCommand, MyResult, MyHandler>(ServiceLifetime.Singleton);

Notifications vs Commands/Queries

  • Commands: Used for operations that change state. Can return results.
  • Queries: Used for read operations. Should not change state.
  • Notifications: Used for domain events. Published to multiple handlers asynchronously.
// Command - changes state, single handler
await _mediator.SendAsync(new CreateUserCommand("John", "john@example.com"));

// Query - reads data, single handler  
var user = await _mediator.QueryAsync(new GetUserQuery(1));

// Notification - publishes event, multiple handlers
await _mediator.PublishAsync(new UserCreatedNotification(1, "John", "john@example.com"));

Performance Considerations

  • Handlers are resolved using reflection, but the resolution is cached for performance
  • Pipeline behaviors are applied in reverse order of registration
  • Notifications are processed concurrently using Task.WhenAll
  • Use appropriate service lifetimes based on your handler dependencies

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog

Version 1.0.1

  • Initial release
  • Commands, queries, and notifications support
  • Pipeline behaviors
  • Dependency injection integration
  • Built-in logging and performance behaviors
Product Compatible and additional computed target framework versions.
.NET net9.0 is compatible.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  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.1 154 6/29/2025
1.0.0 144 6/29/2025