CleanMediator 1.0.1
dotnet add package CleanMediator --version 1.0.1
NuGet\Install-Package CleanMediator -Version 1.0.1
<PackageReference Include="CleanMediator" Version="1.0.1" />
<PackageVersion Include="CleanMediator" Version="1.0.1" />
<PackageReference Include="CleanMediator" />
paket add CleanMediator --version 1.0.1
#r "nuget: CleanMediator, 1.0.1"
#:package CleanMediator@1.0.1
#addin nuget:?package=CleanMediator&version=1.0.1
#tool nuget:?package=CleanMediator&version=1.0.1
CleanMediator
CleanMediator is a lightweight mediator and pipeline behavior library tailored for Clean Architecture projects. It provides structured request/response handling with optional middleware-style pipeline behaviors for pre- and post-processing logic such as logging, validation, caching, etc.
โจ Features
- Minimal setup, zero external dependencies.
- Supports both commands (
IRequest
) and queries (IRequest<T>
) - Pipeline behaviors for clean cross-cutting concerns
- Automatic handler and behavior discovery
- Built-in dependency injection support
- Fully unit-testable
- .NET 8+ compatible
๐ฆ Installation
Install via NuGet:
dotnet add package CleanMediator
๐ Getting Started
1. Register CleanMediator
builder.Services.AddCleanMediator();
This will automatically register:
- All
IRequestHandler<TRequest>
andIRequestHandler<TRequest, TResponse>
implementations - All
IPipelineBehavior<TRequest>
andIPipelineBehavior<TRequest, TResponse>
behaviors
2. Create a Request (Query)
public class GetUserByIdQuery : IRequest<UserResponse>
{
public int Id { get; set; }
}
3. Create a Handler
public class GetUserByIdHandler : IRequestHandler<GetUserByIdQuery, UserResponse>
{
public Task<UserResponse> HandleAsync(GetUserByIdQuery request, CancellationToken cancellationToken)
{
return Task.FromResult(new UserResponse
{
Id = request.Id,
Name = "Jane Doe"
});
}
}
4. Dispatch from Code (Controller)
[Route("api/[controller]")]
[ApiController]
public class UsersController(IRequestDispatcher dispatcher) : ControllerBase
{
private readonly IRequestDispatcher _dispatcher = dispatcher;
[HttpGet("{id}")]
public async Task<IActionResult> GetUserAsync(int id)
{
var result = await _dispatcher.SendAsync(new GetUserByIdQuery{ Id = id });
return Ok(result);
}
}
๐ Commands (No Response)
public class DeactivateUserCommand : IRequest
{
public int UserId { get; set; }
}
public class DeactivateUserHandler : IRequestHandler<DeactivateUserCommand>
{
public Task HandleAsync(DeactivateUserCommand request, CancellationToken cancellationToken)
{
Console.WriteLine($"User {request.UserId} deactivated");
return Task.CompletedTask;
}
}
[HttpPut("{id}")]
public async Task<IActionResult> DeactivateUserAsync(int id)
{
await _dispatcher.SendAsync(new DeactivateUserCommand { UserId = id });
return Ok("User Deactivated Successfully.");
}
๐งฉ Pipeline Behaviors
1. Logging Behavior (Generic)
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
public async Task<TResponse> HandleAsync(TRequest request, Func<Task<TResponse>> next, CancellationToken cancellationToken)
{
Console.WriteLine($"Handling {typeof(TRequest).Name}");
var response = await next();
Console.WriteLine($"Handled {typeof(TRequest).Name}");
return response;
}
}
2. Validation Behavior (Non-Generic)
public class ValidationBehavior<TRequest> : IPipelineBehavior<TRequest>
where TRequest : IRequest
{
public async Task HandleAsync(TRequest request, Func<Task> next, CancellationToken cancellationToken)
{
Console.WriteLine($"Validating {typeof(TRequest).Name}");
await next();
}
}
๐งช Unit Testing
Use xUnit
+ Shouldly
for clean tests:
[Fact]
public async Task Dispatch_GenericRequest_ReturnsExpectedResponse()
{
var services = new ServiceCollection();
services.AddScoped<IRequestDispatcher, RequestDispatcher>();
services.AddScoped<IRequestHandler<GetUserByIdQuery, UserResponse>, GetUserByIdHandler>();
var provider = services.BuildServiceProvider();
var dispatcher = provider.GetRequiredService<IRequestDispatcher>();
var result = await dispatcher.SendAsync(new GetUserByIdQuery { Id = 1 });
result.Name.ShouldBe("Jane Doe");
}
๐ Folder Structure Suggestion
src/
CleanMediator/ --> NuGet package source
test/
CleanMediator.Tests/ --> Unit tests with xUnit and Shouldly
๐ License
This project is licensed under the MIT License.
๐ค Contributing
Contributions are welcome! Please fork, fix, and submit a PR. Open issues if you have questions or suggestions.
๐ Links
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. 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. |
-
net8.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.