DSoftStudio Mediator

← Back to Documentation

Quick Start

1. Define a Request and Handler

public record Ping() : IRequest<int>;

public class PingHandler : IRequestHandler<Ping, int>
{
    public ValueTask<int> Handle(Ping request, CancellationToken ct)
        => new ValueTask<int>(42);
}

2. Register at Startup

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:

  1. Registers core mediator services (IMediator, ISender, IPublisher)
  2. Discovers and registers all handlers across referenced projects
  3. Applies your pipeline configuration via the builder callback
  4. Precompiles dispatch pipelines and freezes dispatch tables

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

Alternative: Step-by-step registration (v1.1.x style)

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 => { ... }) or services.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 with RegisterMediatorHandlers() or PrecompilePipelines() 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<>, and IStreamRequestHandler<,> implementations across all referenced projects — no manual registration required. Each project that references DSoftStudio.Mediator emits [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 calls RegisterMediatorHandlers() (or AddMediator(configure)).

3. Send a Request

var result = await mediator.Send(new Ping());

Required namespaces — which using directives you need depends on the project layer:

Project layer Namespace Why
Domain / Application (handlers, requests) DSoftStudio.Mediator.Abstractions Interfaces: IRequest<T>, ICommand<T>, ISender, etc.
Host / API (startup, DI) DSoftStudio.Mediator.Abstractions + DSoftStudio.Mediator Adds typed Send() / CreateStream() extensions and AddMediator() DI registration

The source generator emits typed extension methods (e.g. Send(Ping)) in the DSoftStudio.Mediator namespace — the host project needs this using to call them.

Tip: add the namespaces your project needs to a GlobalUsings.cs file so every file picks them up automatically.

Features at a Glance

See Also