Mediator.Compat
1.0.2
dotnet add package Mediator.Compat --version 1.0.2
NuGet\Install-Package Mediator.Compat -Version 1.0.2
<PackageReference Include="Mediator.Compat" Version="1.0.2" />
<PackageVersion Include="Mediator.Compat" Version="1.0.2" />
<PackageReference Include="Mediator.Compat" />
paket add Mediator.Compat --version 1.0.2
#r "nuget: Mediator.Compat, 1.0.2"
#:package Mediator.Compat@1.0.2
#addin nuget:?package=Mediator.Compat&version=1.0.2
#tool nuget:?package=Mediator.Compat&version=1.0.2
Mediator.Compat
Lightweight, drop-in replacement for MediatR’s core API
(IRequest, IMediator, INotification, IRequestHandler<>, IPipelineBehavior<>, Unit)
with native reflection-based scanning, deterministic pipeline order, and caching for hot paths.
Install
dotnet add package Mediator.Compat
Quick Start
using Mediator.Compat;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddMediatorCompat(cfg =>
{
cfg.RegisterServicesFromAssembly(typeof(Program).Assembly); // scan handlers/notifications
cfg.AddOpenBehavior(typeof(LoggingBehavior<,>)); // pipeline (outer → inner)
});
var app = builder.Build();
app.MapGet("/ping", async (int x, IMediator mediator) =>
{
var result = await mediator.Send(new Ping(x));
return Results.Ok(result);
});
app.Run();
// ---- app code ----
public sealed record Ping(int X) : IRequest<int>;
public sealed class PingHandler : IRequestHandler<Ping, int>
{
public Task<int> Handle(Ping req, CancellationToken ct) => Task.FromResult(req.X + 1);
}
public sealed class LoggingBehavior<TReq,TRes> : IPipelineBehavior<TReq,TRes> where TReq : IRequest<TRes>
{
private readonly ILogger<LoggingBehavior<TReq, TRes>> _log;
public LoggingBehavior(ILogger<LoggingBehavior<TReq, TRes>> log) => _log = log;
public async Task<TRes> Handle(TReq request, RequestHandlerDelegate<TRes> next, CancellationToken ct)
{
_log.LogInformation("Handling {Request}", typeof(TReq).Name);
var res = await next();
_log.LogInformation("Handled {Request}", typeof(TReq).Name);
return res;
}
}
How DI registration works
AddMediatorCompat(...)registers IMediator and core internals and scans your assemblies for:IRequestHandler<TReq,TRes>INotificationHandler<TNote>
- Behaviors are not auto-registered. Add them explicitly to control order:
services.AddOpenBehavior(typeof(ValidationBehavior<,>));
- Order matters: registration order == execution order (first = outermost).
Behavior pipeline (mental model)
Caller → [Behavior #1] → [Behavior #2] → … → [Handler] → Result
↑ outer ↑ inner
- Behaviors may short-circuit (don’t call
next()), but use sparingly. CancellationTokenflows through every step.
Comparative Benchmarks (vs MediatR 12.x)
Environment: macOS (Apple M4 Pro), .NET 8, BenchmarkDotNet DefaultJob.
Matrix:BehaviorCount ∈ {0, 2},NotificationHandlerCount ∈ {0, 2}.
Full raw output is captured indocs/benchmarks.md(CSV/table).
Headline results
Send (Ping, 0 behaviors)
Mediator.Compat: 66.96 ns / 440 BMediatR: 61.25 ns / 336 B
→ MediatR is ~9% faster; Compat allocates +104 B more. (Baseline “no-pipeline” fast path is our next optimization target.)
Send (Ping, 2 behaviors)
Mediator.Compat: ~105 ns / 800 BMediatR: ~125 ns / 816 B
→ Compat is ~16–17% faster; −16 B less allocation. (Single-closure pipeline pays off.)
Send (Void, 0 behaviors)
Mediator.Compat: 59.31 ns / 296 BMediatR: 59.98 ns / 264 B
→ Essentially a tie on time; Compat is +32 B.
Send (Void, 2 behaviors)
Mediator.Compat: ~88–91 ns / 512 BMediatR: ~116 ns / 600 B
→ Compat is ~22–24% faster; −88 B less allocation.
Publish (Note, 0 handlers)
Mediator.Compat: 21.45 ns / 24 BMediatR: 35.05 ns / 88 B
→ Compat is ~39% faster; −64 B allocation.
Publish (Note, 2 handlers)
Mediator.Compat: ~36.9–40.2 ns / 144 BMediatR: ~78.2–79.6 ns / 464 B
→ Compat is ~2× faster with ~3× less allocation.
Run locally
dotnet run -c Release -p benchmarks/MediatorCompat.Benchmarks
Takeaways
- With pipeline behaviors enabled (≥1),
Mediator.Compatis consistently faster and allocates less. - For Publish, Compat leads both in time and allocation (sequential publish mode).
- In the baseline “no-behavior” Send case, MediatR is slightly ahead; we plan a dedicated no-pipeline fast path to close the gap.
Next optimization targets
- Introduce a no-behavior fast path (skip pipeline construction entirely).
- Cache handler factories (
Func<IServiceProvider, THandler>) to shave a few more nanoseconds off baseline. - Continue allocation dieting in baseline to approach ≤336 B.
See /docs/benchmarks.md for how to run.
Differences vs MediatR (at a glance)
- ✅ Same namespace (
MediatR) & same core interfaces → easy swap. - ✅ No Scrutor; native reflection scanning with duplicate-registration guard.
- ✅ Deterministic behavior order (explicit; no accidental closed-type pickup).
- ✅ Delegate caching per
(TReq,TRes)forSend. - ✅ Single-closure pipeline to minimize per-call allocations.
- ✅ Auto-registration for open generic INotificationHandler<> and IRequestHandler<,>
- 🚧
Publishis sequential-only (parallel mode — backlog/idea).
Target Framework & Tooling
- .NET 8.0+
- Nullable + analyzers recommended.
- Works great with Rider / VS / VS Code.
Links
- NuGet: https://www.nuget.org/packages/Mediator.Compat
- GitHub: https://github.com/rabarba/Mediator.Compat
License
MIT © Ugur Kap
| 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
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.2 | 273 | 9/8/2025 |