Configuration
Dispatch uses the standard .NET configuration patterns with fluent builders for service registration.
Before You Start
-
.NET 8.0+ (or .NET 9/10 for latest features)
-
Install the required packages:
dotnet add package Excalibur.Dispatch -
Familiarity with .NET configuration and dependency injection
Basic Configuration
Service Registration
Register Dispatch in your Program.cs:
var builder = WebApplication.CreateBuilder(args);
// Auto-discover handlers from an assembly (recommended)
builder.Services.AddDispatch(dispatch =>
{
dispatch.AddHandlersFromAssembly(typeof(Program).Assembly);
});
var app = builder.Build();
Configuration Flow
flowchart TD
A[Program.cs] --> B[AddDispatch]
B --> C[IDispatchBuilder]
C --> D[Handler Registration]
C --> E[Middleware Configuration]
C --> F[Pipeline Profiles]
C --> G[Transport Setup]
Using the Dispatch Builder
The main configuration method uses a fluent builder for comprehensive setup:
// Register handlers from assembly with configuration
builder.Services.AddDispatch(dispatch =>
{
// Handler registration
dispatch.AddHandlersFromAssembly(typeof(Program).Assembly);
// Global middleware
dispatch.UseMiddleware<LoggingMiddleware>();
dispatch.UseMiddleware<ValidationMiddleware>();
// Options configuration
dispatch.ConfigureOptions<DispatchOptions>(options =>
{
options.DefaultTimeout = TimeSpan.FromSeconds(30);
});
});
// Serialization: JSON (System.Text.Json) is the default with AddDispatch().
// For binary serialization, install the provider package and register:
// services.AddMemoryPackSerializer();
// services.AddMessagePackSerializer();
Handler Registration
// Single assembly (recommended)
builder.Services.AddDispatch(dispatch =>
{
dispatch.AddHandlersFromAssembly(typeof(Program).Assembly);
});
// Multiple assemblies
builder.Services.AddDispatch(dispatch =>
{
dispatch.AddHandlersFromAssembly(typeof(OrderHandler).Assembly);
dispatch.AddHandlersFromAssembly(typeof(PaymentHandler).Assembly);
});
Middleware Configuration
builder.Services.AddDispatch(dispatch =>
{
dispatch.AddHandlersFromAssembly(typeof(Program).Assembly);
// Add global middleware (applies to all pipelines)
dispatch.UseMiddleware<LoggingMiddleware>();
// Or configure a named pipeline with specific middleware
dispatch.ConfigurePipeline("Actions", pipeline =>
{
pipeline.ForMessageKinds(MessageKinds.Action)
.Use<ValidationMiddleware>()
.Use<AuthorizationMiddleware>();
});
dispatch.ConfigurePipeline("Events", pipeline =>
{
pipeline.ForMessageKinds(MessageKinds.Event);
});
});
When you use UseMiddleware<T>() without explicitly calling ConfigurePipeline(), Dispatch automatically creates a "Default" pipeline containing your global middleware. This means you don't need to configure pipelines for simple scenarios—your middleware is applied to all messages automatically.
Options Configuration
builder.Services.AddDispatch(dispatch =>
{
dispatch.AddHandlersFromAssembly(typeof(Program).Assembly);
// Configure dispatch options
dispatch.ConfigureOptions<DispatchOptions>(options =>
{
options.DefaultTimeout = TimeSpan.FromSeconds(30);
});
});
Ultra-Local Performance Options
Configure direct-local/ultra-local behavior on DispatchOptions.CrossCutting.Performance:
builder.Services.AddDispatch(dispatch =>
{
dispatch.AddHandlersFromAssembly(typeof(Program).Assembly);
dispatch.ConfigureOptions<DispatchOptions>(options =>
{
options.CrossCutting.Performance.DirectLocalContextInitialization =
DirectLocalContextInitializationProfile.Lean; // default
options.CrossCutting.Performance.EmitDirectLocalResultMetadata = false; // default
});
});
Use DirectLocalContextInitializationProfile.Full when you need eager full-context initialization on direct-local paths.
See Ultra-Local Dispatch for dispatch semantics and fallback behavior.
Profile detail:
| Profile | Direct-local initialization behavior |
|---|---|
Lean (default) | Sets Message, correlation/causation (when needed), and skips eager MessageType population |
Full | Same as Lean, plus eager MessageType initialization when missing |
Cross-Cutting Concerns
Configure observability, resilience, caching, and security through the builder:
builder.Services.AddDispatch(dispatch =>
{
dispatch.AddHandlersFromAssembly(typeof(Program).Assembly);
// Observability (tracing, metrics, context flow)
dispatch.UseObservability();
// Resilience (retry, circuit breaker, timeout)
dispatch.UseResilience(res => res.DefaultRetryCount = 3);
// Caching
dispatch.UseCaching();
// Security (requires IConfiguration for reflection-based scanning)
dispatch.UseSecurity(builder.Configuration);
});
When called on IDispatchBuilder, the Dispatch prefix is dropped since it's redundant.
For example, services.AddDispatchObservability() becomes dispatch.UseObservability().
What's Next
- Configuration - Environments & Transports -- appsettings, transports, health checks, observability
- Configuration - Advanced -- ValidateOnStart, builder API reference, common patterns
- Dependency Injection -- DI patterns and lifetimes
- Pipeline -- Middleware configuration details
See Also
- Built-in Middleware -- Pre-built middleware for logging, validation, authorization, and more
- Getting Started -- Step-by-step guide to setting up your first Dispatch project
- Transports -- Transport-specific configuration