dotnet add package DSoftStudio.Mediator
dotnet add package DSoftStudio.Mediator.OpenTelemetry # Distributed tracing + metrics
dotnet add package DSoftStudio.Mediator.FluentValidation # Request validation
dotnet add package DSoftStudio.Mediator.HybridCache # Query caching
All assemblies are signed with PublicKeyToken=6c7e753832e8eb05 (v1.2.0+). This enables:
AddMediator(configure) (and the lower-level RegisterMediatorHandlers()) automatically
discovers all handler implementations (IRequestHandler<,>, INotificationHandler<>,
IStreamRequestHandler<,>, and their CQRS aliases ICommandHandler<,>, IQueryHandler<,>)
across all referenced projects — no manual registration required.
Each project that references DSoftStudio.Mediator emits
[assembly: MediatorHandlerRegistration] attributes at compile time. Downstream projects
read these attributes to build the complete handler registry, without runtime reflection
or assembly scanning.
This works seamlessly with Clean Architecture setups:
Host/API → references Application & Infrastructure
└─ AddMediator(configure) discovers handlers from both
Tip: every project that defines handlers should reference the
DSoftStudio.MediatorNuGet package so the source generator can run and emit the assembly attributes (Phase 1 — fast path). However, projects that only referenceDSoftStudio.Mediator.Abstractionsare still discovered automatically via type-based scanning (Phase 2 — fallback). The host project that callsAddMediator(configure)must always referenceDSoftStudio.Mediator.
The mediator uses two namespaces — which ones you need depends on the project layer:
| Project layer | Namespace | Purpose |
|---|---|---|
| Domain / Application | DSoftStudio.Mediator.Abstractions |
ISender, IMediator, IRequest<T>, ICommand<T>, INotification, handler interfaces |
| Host / API | DSoftStudio.Mediator |
AddMediator() DI extensions, typed Send() / CreateStream() extension methods |
In your host/startup project (where you call AddMediator(configure) and inject ISender), you typically need both:
using DSoftStudio.Mediator.Abstractions; // ISender, IMediator, ICommand<T>, IRequest<T>, etc.
using DSoftStudio.Mediator; // Typed Send() / CreateStream() extensions + AddMediator() DI extensions
In domain or application layer projects (where you define requests, handlers, and inject ISender), only the abstractions namespace is required:
using DSoftStudio.Mediator.Abstractions;
Why the second namespace matters in the host project: the source generator emits typed extension methods (e.g.
Send(MyCommand)) in theDSoftStudio.Mediatornamespace. Without thisusing, the compiler falls back to the genericISender.Send<TRequest, TResponse>()and reports CS0411 because it cannot infer both type arguments.
Tip: add the namespaces you need to a GlobalUsings.cs file so every file in the project picks them up automatically:
// GlobalUsings.cs
global using DSoftStudio.Mediator;
global using DSoftStudio.Mediator.Abstractions;
Both packages ship with IsAotCompatible and IsTrimmable enabled. The hot execution path uses no reflection, no MakeGenericType, no Expression.Compile, and no dynamic method generation — all handler discovery and dispatch wiring are performed at compile time by Roslyn source generators.
This makes the mediator suitable for:
The Publish(object) and Send(object) overloads (runtime-typed dispatch) are also AOT-safe — they use compile-time generated FrozenDictionary<Type, DispatchDelegate> dispatch tables populated by the source generator, with no MakeGenericType at runtime.
AddMediator(configure) vs step-by-step registration