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" />
<PackageReference Include="Alvi.Mediator" />
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
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#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
#tool nuget:?package=Alvi.Mediator&version=1.0.1
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Alvi.Mediator
A lightweight, high-performance CQRS mediator pattern implementation for .NET applications. Supports commands, queries, notifications, and pipeline behaviors.
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 | Versions 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.
-
net9.0
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.