Released in v1.0.7
DI-based mediators (including DSoftStudio.Mediator) can fail to resolve handlers at runtime if a handler or its dependencies throw during construction. By default, this failure is only detected when the handler is first resolved (e.g., on the first request), which can make misconfiguration hard to diagnose and affect unrelated requests. A fail-fast pattern is desired: all handlers should be validated at startup, and the app should fail immediately if any handler cannot be constructed.
DSoftStudio.Mediator provides fail-fast handler validation at startup via a source-generated ValidateMediatorHandlers() extension method on IServiceProvider. This approach was chosen over IHostedService to avoid adding a dependency on Microsoft.Extensions.Hosting.Abstractions to the core package.
The DependencyInjectionGenerator (Roslyn incremental source generator) emits two additional types alongside the existing MediatorServiceRegistry:
| Generated Type | Purpose |
|---|---|
MediatorHandlerValidator |
Static class with Validate(IServiceProvider) — resolves every registered handler from DI |
MediatorHandlerValidatorExtensions |
Extension method ValidateMediatorHandlers(this IServiceProvider) |
For each handler type discovered at compile time:
| Handler Category | Validation Method | What it validates |
|---|---|---|
IRequestHandler<TReq, TRes> |
GetRequiredService<T>() |
Handler + all constructor dependencies |
PipelineChainHandler<TReq, TRes> |
GetService<T>() (nullable) |
Pipeline chain + all behaviors, processors, exception handlers |
INotificationHandler<TNotif> |
GetServices<T>() + enumerate |
All handler implementations for each notification type |
IStreamRequestHandler<TReq, TRes> |
GetRequiredService<T>() |
Stream handler + dependencies |
StreamPipelineChainHandler<TReq, TRes> |
GetService<T>() (nullable) |
Stream pipeline chain if registered |
All failures are collected into a List<Exception> and thrown as a single AggregateException after all handlers have been validated. This reports all misconfigured handlers at once, not just the first failure.
// ASP.NET Core
var app = builder.Build();
app.Services.ValidateMediatorHandlers(); // Throws AggregateException on failure
app.Run();
// Console / test
var provider = services.BuildServiceProvider();
provider.ValidateMediatorHandlers();
Microsoft.Extensions.Hosting.Abstractions requiredMakeGenericTypeValidateMediatorHandlers() explicitly.IHostedService can trivially wrap the call in their own hosted service.List<string>, counters) must have those dependencies registered for validation to pass.| Test | Result |
|---|---|
| Happy path (all handlers resolve) | ✅ Pass |
Missing handlers → AggregateException |
✅ Pass |
| Aggregate contains all failures | ✅ Pass |
| Performance regression (allocation) | ✅ No impact — Send=72B, Publish=0B |
| Performance regression (throughput) | ✅ No impact |
| Full test suite (174 tests) | ✅ 0 regressions |
| Date | Version | Changes |
|---|---|---|
| — | Draft | Initial ADR with implementation plan |
| 2026-03-15 | v1.0.7 | Released with source-generated startup validation |