public record Ping() : IRequest<int>;
public class PingHandler : IRequestHandler<Ping, int>
{
public ValueTask<int> Handle(Ping request, CancellationToken ct)
=> new ValueTask<int>(42);
}
services.AddMediator(builder =>
{
// Register pipeline behaviors, processors, etc.
builder.AddOpenBehavior(typeof(LoggingBehavior<,>));
builder.AddRequestPreProcessor<ValidationPreProcessor>();
builder.AddParallelNotificationPublisher();
});
No behaviors to register? You still need the builder callback — pass an empty lambda:
services.AddMediator(_ => { });This registers handlers, precompiles pipelines, and freezes dispatch — all in one call. Without the callback,
AddMediator()only registers core services and you must complete the setup manually (see step-by-step registration below).
AddMediator(configure) is a single entry point that automatically:
IMediator, ISender, IPublisher)Available builder methods:
| Method | Purpose |
|---|---|
AddOpenBehavior(Type, ServiceLifetime) |
Open-generic IPipelineBehavior<,> |
AddStreamBehavior<T>(ServiceLifetime) |
Closed IStreamPipelineBehavior<,> |
AddRequestPreProcessor<T>(ServiceLifetime) |
IRequestPreProcessor<T> |
AddRequestPostProcessor<T>(ServiceLifetime) |
IRequestPostProcessor<T,R> |
AddRequestExceptionHandler<T>(ServiceLifetime) |
IRequestExceptionHandler<T,R> |
AddParallelNotificationPublisher() |
Replace sequential with Task.WhenAll dispatch |
If you omit the builder callback, AddMediator() only registers core services (IMediator, ISender, IPublisher). You must chain the remaining steps yourself:
services
.AddMediator() // Core services only
.RegisterMediatorHandlers(); // Discover and register all handlers
// Register behaviors, processors, etc.
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>));
services
.PrecompilePipelines() // Build dispatch table and freeze
.PrecompileNotifications()
.PrecompileStreams();
This pattern remains fully supported for advanced scenarios where you need to insert registrations between steps.
Summary
Pattern Call What it does Builder (recommended) services.AddMediator(builder => { ... })orservices.AddMediator(_ => { })Everything: core + handlers + builder config + precompile + freeze Manual (v1.1.x) services.AddMediator().RegisterMediatorHandlers().PrecompilePipelines()User controls each step
Do not mix both approaches. Using
AddMediator(configure)together withRegisterMediatorHandlers()orPrecompilePipelines()causes redundant registrations. The compile-time diagnostic DSOFT007 will warn you if mixed usage is detected. See Registration Order for details.
Cross-project handler discovery. Both approaches automatically discover all
IRequestHandler<,>,INotificationHandler<>, andIStreamRequestHandler<,>implementations across all referenced projects — no manual registration required. Each project that referencesDSoftStudio.Mediatoremits[assembly: MediatorHandlerRegistration]attributes at compile time, and downstream projects read them to build the complete handler registry. This works for Clean Architecture setups where handlers live in Application or Infrastructure layers and the host/API project only callsRegisterMediatorHandlers()(orAddMediator(configure)).
var result = await mediator.Send(new Ping());
Required namespaces — which
usingdirectives you need depends on the project layer:
Project layer Namespace Why Domain / Application (handlers, requests) DSoftStudio.Mediator.AbstractionsInterfaces: IRequest<T>,ICommand<T>,ISender, etc.Host / API (startup, DI) DSoftStudio.Mediator.Abstractions+DSoftStudio.MediatorAdds typed Send()/CreateStream()extensions andAddMediator()DI registrationThe source generator emits typed extension methods (e.g.
Send(Ping)) in theDSoftStudio.Mediatornamespace — the host project needs thisusingto call them.Tip: add the namespaces your project needs to a
GlobalUsings.csfile so every file picks them up automatically.
IRequest<TResponse> and IRequestHandler<TRequest, TResponse>IPipelineBehavior<TRequest, TResponse>IRequestPreProcessor<TRequest> and IRequestPostProcessor<TRequest, TResponse>IRequestExceptionHandler<TRequest, TResponse>INotification and INotificationHandler<TNotification>INotificationPublisher (sequential or parallel)IStreamRequest<TResponse> and IStreamRequestHandler<TRequest, TResponse>IStreamPipelineBehavior<TRequest, TResponse>ICommand<TResponse>, IQuery<TResponse>, ICommandHandler, and IQueryHandler aliasesstatic Execute method inside the request class, no separate handler neededSend(object) dispatch for message bus / command queue scenarios — AOT-safe, no reflectionISender and IPublisher for narrower DI injectionUnit type for void-returning commands (ICommand<Unit>)ValidateMediatorHandlers() — detect misconfigured handlers at startupMediatorBuilder fluent API — single-call AddMediator(configure) with AddOpenBehavior, AddRequestPreProcessor, AddParallelNotificationPublisher, and morePublicKeyToken=6c7e753832e8eb05 for enterprise compatibilityPrecompile* methodsICommand<T> and IQuery<T> for semantic clarity