Table of Contents

Registration and lifetimes

Dispatcher and handlers are scoped by default. Resolve them inside a DI scope, as ASP.NET Core does for each request.

Scanning an assembly

The usual setup registers infrastructure and then scans one or more assemblies:

builder.Services
    .AddDispatcher()
    .AddDispatcherHandlers(typeof(Program).Assembly);

AddDispatcher() registers infrastructure only and never scans assemblies implicitly. AddDispatcherHandlers() registers internal handler classes. Registering the same assembly more than once is safe.

Registering a single handler

A single handler can be registered explicitly instead of scanning for it:

using Dispatcher;

builder.Services.AddQueryHandler<GetGreetingQuery, string, GetGreetingQueryHandler>();

There is one method per handler kind: AddQueryHandler, AddCommandHandler, and AddNotificationHandler.

Note

Registering handlers only through the typed methods means Dispatcher may not know about derived message types. See route targets.

Setting lifetimes

Each registration method takes an optional delegate that sets the handler lifetime, and assembly scanning takes the same delegate:

builder.Services.AddQueryHandler<GetGreetingQuery, string, GetGreetingQueryHandler>(options =>
    options.ServiceLifetime = ServiceLifetime.Singleton);

builder.Services.AddDispatcherHandlers(
    typeof(Program).Assembly,
    options => options.ServiceLifetime = ServiceLifetime.Singleton);

The dispatcher itself is configured the same way, for applications that need a new instance for every resolution:

builder.Services.AddDispatcher(options =>
    options.ServiceLifetime = ServiceLifetime.Transient);

Which lifetimes are accepted

Which lifetimes are accepted differs by what is being registered:

Registered Scoped Transient Singleton
Dispatcher ✅ ✅ ❌ rejected
Handlers ✅ ✅ ✅
Important

A singleton dispatcher is rejected because it would capture the root service provider and could not safely resolve scoped handlers or pipeline behaviors.

Pipeline behaviors are configured independently of both, through their own registration methods.

DispatcherOptions and DispatcherTelemetryOptions are in the Dispatcher namespace and ship in the core Send0xx.Dispatcher package.