PMQ.Mediator
1.1.2
dotnet add package PMQ.Mediator --version 1.1.2
NuGet\Install-Package PMQ.Mediator -Version 1.1.2
<PackageReference Include="PMQ.Mediator" Version="1.1.2" />
<PackageVersion Include="PMQ.Mediator" Version="1.1.2" />
<PackageReference Include="PMQ.Mediator" />
paket add PMQ.Mediator --version 1.1.2
#r "nuget: PMQ.Mediator, 1.1.2"
#:package PMQ.Mediator@1.1.2
#addin nuget:?package=PMQ.Mediator&version=1.1.2
#tool nuget:?package=PMQ.Mediator&version=1.1.2
PMQ.Mediator
A lightweight mediator pattern implementation for .NET applications with FluentValidation integration, request/response pipeline behaviors, streaming support, and notification publishing.
Features
- 🚀 Request/Response - Send commands and queries with typed responses
- 📡 Notifications - Fan-out pub/sub with multiple handlers per event
- 🔄 Async Streams -
IAsyncEnumerable<T>support viaIStreamRequest<T> - ✅ Validation - Built-in FluentValidation pipeline behavior
- 📋 Logging - Built-in logging behavior with execution time tracking
- 🔗 Pipeline Behaviors - Middleware-style composition for requests and streams
- 🔍 Assembly Scanning - Auto-discovers handlers with prefix filtering
- ⚙️ Highly Configurable - Lifetime, culture, custom validation failure handling
Installation
dotnet add package PMQ.Mediator
Quick Start
1. Register the Mediator
In your Program.cs:
builder.Services.AddPmqMediator(options =>
{
options.RegisterServicesFromAssemblies(typeof(CreateOrderCommand).Assembly);
options.UseValidationBehavior = true;
options.UseLoggingBehavior = true;
});
2. Define a Request and Handler
public record CreateOrderCommand(string CustomerName, decimal Amount) : IRequest<OrderResult>;
public class CreateOrderCommandHandler : IRequestHandler<CreateOrderCommand, OrderResult>
{
public Task<OrderResult> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
{
// your logic here
return Task.FromResult(new OrderResult(Guid.NewGuid()));
}
}
3. Send the Request
public class OrderController(IMediator mediator) : ControllerBase
{
[HttpPost]
public async Task<IActionResult> Create(CreateOrderCommand command)
{
var result = await mediator.Send(command);
return Ok(result);
}
}
Core Concepts
Request/Response
Use IRequest<TResponse> for commands/queries that return a value, or IRequest for fire-and-forget:
// With response
public record GetUserQuery(int Id) : IRequest<UserDto>;
// Void (no response)
public record DeleteUserCommand(int Id) : IRequest;
Notifications
Notifications are dispatched to all registered handlers (fan-out):
public record OrderCreatedEvent(Guid OrderId) : INotification;
public class SendEmailHandler : INotificationHandler<OrderCreatedEvent>
{
public Task Handle(OrderCreatedEvent notification, CancellationToken cancellationToken)
{
// send email
return Task.CompletedTask;
}
}
// Publish
await mediator.Publish(new OrderCreatedEvent(orderId));
Async Streams
Stream results using IAsyncEnumerable<T>:
public record GetItemsQuery : IStreamRequest<ItemDto>;
public class GetItemsHandler : IStreamRequestHandler<GetItemsQuery, ItemDto>
{
public async IAsyncEnumerable<ItemDto> Handle(GetItemsQuery request,
[EnumeratorCancellation] CancellationToken cancellationToken)
{
await foreach (var item in GetItemsAsync(cancellationToken))
yield return item;
}
}
// Consume
await foreach (var item in mediator.CreateStream(new GetItemsQuery()))
{
Console.WriteLine(item);
}
Pipeline Behaviors
Create custom behaviors that wrap request handling (like middleware):
public class MyCustomBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
public async Task<TResponse> Handle(TRequest request,
RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
// before
var response = await next();
// after
return response;
}
}
Configuration
builder.Services.AddPmqMediator(options =>
{
// Assembly scanning
options.RegisterServicesFromAssemblies(assembly1, assembly2);
options.RegisterServicesFromAssemblyContaining<MyHandler>();
options.RegisterServicesFromAssemblyPrefixes("MyCompany.", "MyProject");
// Service lifetime (default: Scoped)
options.Lifetime = ServiceLifetime.Scoped;
// Built-in pipeline behaviors
options.UseValidationBehavior = true;
options.UseLoggingBehavior = true;
// FluentValidation culture
options.ValidatorCulture = new CultureInfo("pt-BR");
// Custom validation failure handler
options.ValidationFailureHandlerType = typeof(CustomFailureHandler<>);
});
| Option | Default | Description |
|---|---|---|
Lifetime |
Scoped |
DI lifetime for IMediator |
UseValidationBehavior |
false |
Enable automatic FluentValidation |
UseLoggingBehavior |
false |
Enable request logging with timing |
ValidatorCulture |
null |
Culture for validation error messages |
ValidationFailureHandlerType |
null |
Custom handler for validation failures |
Validation
When UseValidationBehavior is enabled, all registered IValidator<TRequest> validators are executed before the handler. If validation fails, a ValidationException is thrown — unless a custom IValidationFailureHandler<TResponse> is registered:
public class NotificationFailureHandler<TResponse> : IValidationFailureHandler<TResponse>
{
public TResponse HandleFailure(IEnumerable<ValidationFailure> failures)
{
// Transform failures into your domain error response
}
}
License
This project is licensed under the MIT License.
| 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 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
- FluentValidation.DependencyInjectionExtensions (>= 12.1.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 10.0.10)
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.10)
-
net8.0
- FluentValidation.DependencyInjectionExtensions (>= 12.1.1)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.3)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on PMQ.Mediator:
| Package | Downloads |
|---|---|
|
PMQ.Domain
Domain-Driven Design building blocks for .NET: entities with identity-based equality, aggregate roots, value objects and domain events. Validation is accumulated as notifications instead of thrown as exceptions. |
GitHub repositories
This package is not used by any popular GitHub repositories.