MeliorDispatch 1.0.1
dotnet add package MeliorDispatch --version 1.0.1
NuGet\Install-Package MeliorDispatch -Version 1.0.1
<PackageReference Include="MeliorDispatch" Version="1.0.1" />
<PackageVersion Include="MeliorDispatch" Version="1.0.1" />
<PackageReference Include="MeliorDispatch" />
paket add MeliorDispatch --version 1.0.1
#r "nuget: MeliorDispatch, 1.0.1"
#:package MeliorDispatch@1.0.1
#addin nuget:?package=MeliorDispatch&version=1.0.1
#tool nuget:?package=MeliorDispatch&version=1.0.1
MeliorDispatch
A production-ready, high-performance mediator library for .NET 8/9/10 — a drop-in replacement for MediatR with Native AOT support, source-generated registration, and zero-reflection dispatch.
Status: Phases 1-11 complete (core abstractions, request/notification/stream dispatch, pipeline behaviors, dependency injection, source generator, Roslyn analyzers, benchmarks, samples, documentation). See the repository's phase plan for details.
Documentation
- Migration guide from MediatR
- API reference
- Performance guide — the two dispatch paths, what's AOT-safe today and what isn't yet
- Best practices
- FAQ
Packages
Everything ships in a single NuGet package, MeliorDispatch — install one package and you're done.
Internally it's built from two assemblies, mirroring MediatR's own split between its contracts and implementation:
MeliorDispatch.Abstractions— the public contract only:IRequest,INotification, handler interfaces, pipeline behavior interfaces, attributes. No implementation details.MeliorDispatch— the mediator implementation andIServiceCollectionregistration extensions. Most of its types areinternal, so they don't leak into consumers' IntelliSense or object browser.
The MeliorDispatch.Abstractions project is never packed or published on its own; its build output is merged
into the MeliorDispatch package (lib/<tfm>/MeliorDispatch.Abstractions.dll alongside MeliorDispatch.dll), so
there is exactly one package reference and no separate abstractions dependency to manage.
The Roslyn source generator (MeliorDispatch.SourceGenerator) and analyzers (MeliorDispatch.Analyzers) are
delivered as build-time-only assets bundled inside this same package under analyzers/dotnet/cs/, so
consuming projects only ever need <PackageReference Include="MeliorDispatch" /> - no separate package
reference activates either one.
Source generator
Referencing MeliorDispatch automatically gets you the generator. It discovers request/notification/stream
handlers declared in your project and emits, per assembly:
- A
[ModuleInitializer]that registers a compile-time-known dispatch wrapper per handler viaMeliorDispatch.GeneratedHandlerRegistry, so dispatch for those request types needs noType.MakeGenericType/reflection at runtime. - An
AddGeneratedMediatorHandlers(IServiceCollection)extension method - call it alongsideAddMediator()for handler registration with no assembly scanning:services.AddMediator().AddGeneratedMediatorHandlers();.
Analyzers
| ID | What it flags |
|---|---|
| MELIORDISP001 | Duplicate handler for the same request type (reported by the source generator). |
| MELIORDISP002 | A request/stream request has no handler anywhere in the compilation. Has a code fix that scaffolds a handler stub. |
| MELIORDISP003 | A handler/behavior Sends the same request type it is handling, from inside its own Handle method (likely infinite recursion). |
| MELIORDISP004 | A pipeline behavior/processor/exception handler-action never appears to be registered. |
| MELIORDISP005 | Contradictory or unreachable IRequestHandler interface combination. |
| MELIORDISP006 | A Singleton-lifetime handler declares a mutable instance field. |
| MELIORDISP007 | A request type is never constructed anywhere in the compilation. |
| MELIORDISP008 | A Handle method never references its CancellationToken parameter. |
Benchmarks
src/MeliorDispatch.Benchmarks uses BenchmarkDotNet to compare MeliorDispatch against MediatR head-to-head on
identically-shaped fixtures, measuring latency, allocations, and throughput via [MemoryDiagnoser]:
SendBenchmarks— single request/response dispatch against a pre-built service provider.PublishBenchmarks— notification fan-out to three handlers (Sequential strategy on both sides).StartupBenchmarks— the one-time cost of registering handlers and building the container, since that's a different cost profile than steady-state dispatch and shouldn't be conflated with it.
Run the full suite (this takes several minutes - BenchmarkDotNet does multiple warmup/measurement iterations per benchmark to get statistically sound numbers):
dotnet run -c Release --project src/MeliorDispatch.Benchmarks
Run a single class, or use BenchmarkDotNet's fast --job dry mode to sanity-check the harness itself
without waiting for real measurements:
dotnet run -c Release --project src/MeliorDispatch.Benchmarks -- --filter "*SendBenchmarks*"
This project is intentionally the single consolidated benchmarks project; the original phase plan also
mentions a tests/BenchmarkTests folder, which would just duplicate its job (BenchmarkDotNet benchmarks
are the performance tests here), so a second copy was not created.
Samples
Five runnable samples under samples/, each demonstrating a different hosting model:
ConsoleSample— the smallest possible tour:Send,Publishto multiple handlers,CreateStream, and an open-generic loggingIPipelineBehavior<,>registered viaRegisterPipeline. Run withdotnet run --project samples/ConsoleSample.WebApiSample— a controller-based ASP.NET Core API (a small Todo API) where the controller only callsISender.Send; aCreateTodocommand publishes aTodoCreatednotification that a separate logging handler reacts to, so the write path and the logging concern stay decoupled. Run withdotnet run --project samples/WebApiSampleandPOST/GET/todos.MinimalApiSample— minimal API endpoints callingISenderdirectly, includingGET /weather/streamwhich returnssender.CreateStream(...)straight from the endpoint delegate - ASP.NET Core serializes theIAsyncEnumerable<T>as it's produced.WorkerServiceSample— aBackgroundServiceon aPeriodicTimer. The important detail here is that the worker is a singleton but creates anIServiceScopeFactoryscope per tick before resolvingIMediator, exactly as an ASP.NET Core request scope would - a common source of subtle bugs if skipped.AzureFunctionsSample— an isolated-worker Azure Function with an HTTP trigger, registeringAddMediatorthe same way any other host does inProgram.cs. Requires the Azure Functions Core Tools to run locally (func startfrom the project folder); itslocal.settings.jsonpoints at the storage emulator and contains no real secrets, so it's checked in as-is.
All five were built and actually run (not just compiled) as part of verifying this phase - including
hitting the WebApiSample/MinimalApiSample/AzureFunctionsSample endpoints with curl and observing the
WorkerServiceSample's log output tick.
License
MIT
| 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 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 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
-
net8.0
-
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.