Fast mediator for handling requests, commands, notifications, and streams with ValueTask and ordered pipelines
- Supports
IRequest<TResponse>andIRequest(void-style) - Custom handlers via
IRequestHandler<,>andIRequestHandler<> - Supports both
ValueTask(for modern, efficient handlers) andTask(for compatibility with MediatR-style handlers) - Enables middleware-style pipelines using
IPipelineBehavior<TRequest, TResponse>. A pipeline behavior can be defined for all or specific request types. - Supports
INotificationHandlerwith serial and parallel publishing - Ordered execution of pipeline behaviors
- Simple registration through
AddMitMediator()or assembly scanning - Supports
IStreamRequestHandleandIStreamPipelineBehavior
dotnet add package MitMediator -v 10.0.0This example shows a basic setup of MitMediator that demonstrates:
- Request handling via PingRequestHandler
- Notification publishing via NotificationHandler
- Two pipeline behaviors: HeightBehavior and LowBehavior
using Microsoft.Extensions.DependencyInjection;
using MitMediator;
var services = new ServiceCollection();
services
.AddMitMediator(typeof(PingRequestHandler).Assembly)
.AddTransient(typeof(IPipelineBehavior<,>), typeof(HeightBehavior<,>))
.AddTransient(typeof(IPipelineBehavior<,>), typeof(LowBehavior<,>));
var provider = services.BuildServiceProvider();
var mediator = provider.GetRequiredService<IMediator>();
// HeightBehavior: Handling PingRequest
// LowBehavior: Handling PingRequest
// PingRequestHandler: Pong
// NotificationHandler: Notification!
// LowBehavior: Handled PingRequest
// HeightBehavior: Handled PingRequest
string result = await mediator.SendAsync<PingRequest, string>(new PingRequest(), CancellationToken.None);
Console.WriteLine(result); //Pong result
public class PingRequest : IRequest<string> { }
public class PingRequestHandler : IRequestHandler<PingRequest, string>
{
private readonly IMediator _mediator;
public PingRequestHandler(IMediator mediator)
{
_mediator = mediator;
}
public ValueTask<string> HandleAsync(PingRequest request, CancellationToken cancellationToken)
{
Console.WriteLine("PingRequestHandler: Pong");
_mediator.PublishAsync(new Notification(), cancellationToken);
return ValueTask.FromResult("Pong result");
}
}
public class LowBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
public async ValueTask<TResponse> HandleAsync(TRequest request, IRequestHandlerNext<TRequest, TResponse> next, CancellationToken cancellationToken)
{
Console.WriteLine($"LowBehavior: Handling {typeof(TRequest).Name}");
var result = await next.InvokeAsync(request, cancellationToken);
Console.WriteLine($"LowBehavior: Handled {typeof(TRequest).Name}");
return result;
}
}
public class HeightBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
public async ValueTask<TResponse> HandleAsync(TRequest request, IRequestHandlerNext<TRequest, TResponse> next, CancellationToken cancellationToken)
{
Console.WriteLine($"HeightBehavior: Handling {typeof(TRequest).Name}");
var result = await next.InvokeAsync(request, cancellationToken);
Console.WriteLine($"HeightBehavior: Handled {typeof(TRequest).Name}");
return result;
}
}
public class Notification : INotification{}
public class NotificationHandler : INotificationHandler<Notification>
{
public ValueTask HandleAsync(Notification notification, CancellationToken cancellationToken)
{
Console.WriteLine($"NotificationHandler: Notification!");
return ValueTask.CompletedTask;
}
}To use
Taskinstead ofValueTaskfor handlers, reference the MitMediator.Tasks namespace
You can reuse your existing handlers with minimal modifications — just update the namespaces and registration calls
- Add the
MitMediatorpackagedotnet add package MitMediator -v 10.0.0 - In your request files, replace the namespace
MediatRwithMitMediator - In your request handler files, replace the namespace
MediatRwithMitMediator(andMitMediator.TasksforTaskresult) - Update your dependency injection setup: replace
.AddMediatR(...)with.AddMitMediator() - If you're implementing
INotificationHandler, useValueTaskinstead ofTask - If you're implementing
IPipelineBehavior, useValueTaskinstead ofTaskandIRequestHandlerNext<TRequest, TResponse>instead ofRequestHandlerDelegate<TResponse>. Usenext.InvokeAsync(request, cancellationToken)for next pipe - For handlers with void result, use
Task<Unit>instead ofTask(returnUnit.Value) - (Optional) Change all
mediator.Send(request, ct)tomediator.SendAsync<TRequset, TResponse>(request, ct)(ormediator.Send<TRequset, TResponse>(request, ct)forTaskresult) - Build and run your project — you’re all set!
Use
SendAsync<TRequset, TResponse>(request, ct)for best performance orSend(request, ct)for backward compatibility with MediatR-style semantics
MitMediator is designed to feel familiar for those coming from MediatR. Core concepts like IRequest, IRequestHandle, and pipeline behaviors are preserved — but with a cleaner interface and support for ValueTask out of the box.
| Mediator | Method | Mean (ns) | Allocated (B) |
|---|---|---|---|
| MediatR | Send (return result) | 91.64 | 272 |
| MitMediator | SendAsync (return result) | 40.60 | 0 |
| MediatR | Send (return result, use behaviors) | 191.82 | 800 |
| MitMediator | SendAsync (return result, use behaviors) | 40.49 | 0 |
| MediatR | Send (Return void) | 77.73 | 128 |
| MitMediator | SendAsync (Return void) | 36.73 | 0 |
| MediatR | Publish | 138.79 | 592 |
| MitMediator | PublishAsync | 51.74 | 32 |
| MediatR | CreateStream (return stream, use behavior) | 809.3 | 1168 |
| MitMediator | CreateStream (return stream, use behavior) | 187.0 | 112 |
| Feature | MitMediator | MediatR |
|---|---|---|
| Return types | ValueTask (default, allocation-friendly) |
Task (standard async support) |
| Send methods | Strongly typed requests (SendAsync<TRequest, TResponse>) |
Loosely typed requests (Send(request)) |
| DI Registration | AddMitMediator() with optional assembly scanning |
AddMediatR() with assemblies explicitly specified |
| Extensibility | Designed for lightweight extension and customization | More opinionated; extensibility requires deeper integration |
| Notification publishing | Serial and parallel | Only serial out of the box |
| Performance Focus | Async-first, zero-allocation for ValueTask |
Flexible but not optimized for ValueTask |
| License & Availability | MIT | Reciprocal Public License 1.5 (RPL1.5) and commercial license |
- MitMediator.AutoApi - auto-registers API endpoints and generates HTTP clients from request types
- MitMediator.AppAuthorize - simplifies authentication and authorization via basic auth or JWT bearer tokens
- MitMediator.InMemoryCache - attribute-driven in-memory caching extension
MIT