BuildingBlocks.Mediator
1.1.0
dotnet add package BuildingBlocks.Mediator --version 1.1.0
NuGet\Install-Package BuildingBlocks.Mediator -Version 1.1.0
<PackageReference Include="BuildingBlocks.Mediator" Version="1.1.0" />
<PackageVersion Include="BuildingBlocks.Mediator" Version="1.1.0" />
<PackageReference Include="BuildingBlocks.Mediator" />
paket add BuildingBlocks.Mediator --version 1.1.0
#r "nuget: BuildingBlocks.Mediator, 1.1.0"
#:package BuildingBlocks.Mediator@1.1.0
#addin nuget:?package=BuildingBlocks.Mediator&version=1.1.0
#tool nuget:?package=BuildingBlocks.Mediator&version=1.1.0
BuildingBlocks.Mediator
CQRS-first Send + ordered pipeline for .NET 8+. Commands and queries, host-owned behaviors, optional traces and metrics, startup handler checks.
When to use: you want manual pipeline order, typed command/query behaviors, optional OpenTelemetry around Send, and a built-in scanner (no Scrutor).
What's new in 1.1.0
- Typed
ICommandPipelineBehavior/IQueryPipelineBehavior— MS.DI does not construct the opposite kind AddOpenCommandBehavior/AddOpenQueryBehaviorfail fast when the type is unconstrained- Opt-in Send metrics on
UseTelemetry()(histogrammediator.send.duration, countermediator.send) - Drop-in from 1.0.1 (
CommandPipelineBehavior/QueryPipelineBehaviorunchanged)
Features
- CQRS markers:
ICommand/ICommand<T>/IQuery<T>(no non-genericIQuery) - Void commands:
ICommand : ICommand<Unit>— pipeline binds to the real command type - Ordered pipeline: open/closed behaviors with optional
order(lower = outermost) - Typed command/query behaviors:
ICommandPipelineBehavior/IQueryPipelineBehavior— MS.DI does not construct them for the opposite kind - 1.0 filter bases still work:
CommandPipelineBehavior/QueryPipelineBehaviorskip the other kind at runtime UseTelemetry(): optional ActivitySource + Meter around Send (not a pipeline behavior)ValidateOnStartup: missing/duplicate handlers at registration- Exact-one handler at Send, with clear errors
- Open-generic handlers closed on demand
- Built-in scanner — no Scrutor
- Roslyn analyzers BBM001 / BBM002 packed in the NuGet
Install
dotnet add package BuildingBlocks.Mediator
Requires .NET 8, .NET 9, or .NET 10.
Quick start
1. Define a command and handler
public sealed record CreateOrder(string Product, int Qty) : ICommand<OrderId>;
public sealed class CreateOrderHandler : ICommandHandler<CreateOrder, OrderId>
{
public Task<OrderId> Handle(CreateOrder command, CancellationToken ct)
=> Task.FromResult(new OrderId(Guid.NewGuid()));
}
2. Register
services.AddMediator(cfg =>
{
cfg.RegisterServicesFromAssemblyContaining<CreateOrderHandler>();
cfg.AddOpenBehavior(typeof(ValidationBehavior<,>), order: 0); // host-owned
cfg.UseTelemetry(); // traces + metrics (omit for zero overhead)
cfg.ValidateOnStartup = true;
});
3. Send — prefer ISender at call sites
await sender.Send(new CreateOrder("SKU-1", 2), ct);
var dto = await sender.Send(new GetOrder(id), ct);
await sender.Send(new CancelOrder(id), ct); // ICommand (void)
Command-only vs query-only behaviors
Use constrained interfaces so a caching behavior is never constructed for a write, and an audit/transaction behavior is never constructed for a read:
public sealed class AuditCommands<TCommand, TResponse> : ICommandPipelineBehavior<TCommand, TResponse>
where TCommand : ICommand<TResponse>
{
public async Task<TResponse> Handle(
TCommand command, RequestHandlerDelegate<TResponse> next, CancellationToken ct)
=> await next(ct);
}
public sealed class CacheQueries<TQuery, TResponse> : IQueryPipelineBehavior<TQuery, TResponse>
where TQuery : IQuery<TResponse>
{
public async Task<TResponse> Handle(
TQuery query, RequestHandlerDelegate<TResponse> next, CancellationToken ct)
=> await next(ct);
}
cfg.AddOpenCommandBehavior(typeof(AuditCommands<,>), order: 10);
cfg.AddOpenQueryBehavior(typeof(CacheQueries<,>), order: 20);
// AddOpenBehavior(typeof(AuditCommands<,>)) also works — the constraint is on the type
CommandPipelineBehavior / QueryPipelineBehavior from 1.0.1 remain supported (runtime skip). Prefer the interfaces for new code.
Telemetry
UseTelemetry() wraps pipeline + handler (not a behavior):
- Traces: ActivitySource
BuildingBlocks.Mediator - Metrics: Meter
BuildingBlocks.Mediator— histogrammediator.send.duration(ms), countermediator.send(mediator.success,mediator.message_kind,mediator.request_name)
cfg.UseTelemetry(o =>
{
o.ActivitySourceName = "BuildingBlocks.Mediator"; // MeterName copies this when unset
o.EnableMetrics = true; // default
o.EnableLogging = true;
o.RecordException = true;
});
Host OpenTelemetry (or BuildingBlocks.Telemetry with IntegrateMediator = true):
.WithTracing(t => t.AddSource("BuildingBlocks.Mediator"))
.WithMetrics(m => m.AddMeter("BuildingBlocks.Mediator"));
Omit UseTelemetry() for zero library telemetry overhead. Set EnableMetrics = false to keep traces without meters.
Validation stays host-owned (FluentValidation + AddOpenBehavior). See the cookbook.
What it is not (v1)
- Not a MediatR or messaging replacement
- No
Publish/INotification(use your event bus) - No streaming (
CreateStream) - No exception handlers that replace results (faults rethrow)
- No built-in FluentValidation
- Not fully Native AOT (runtime
MakeGenericTypewrappers) - Open-generic handlers always resolve as Transient (ignore
HandlerLifetime)
Docs
Demo host: FeatureFusion in the same repository.
License
MIT — Copyright (c) 2026 Mohammad Hasan Hosseini
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
-
net8.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
-
net9.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.1)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.2)
- Microsoft.Extensions.Options (>= 8.0.2)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
1.1.0: Typed ICommandPipelineBehavior/IQueryPipelineBehavior; AddOpenCommandBehavior/AddOpenQueryBehavior; opt-in Send metrics (mediator.send.duration, mediator.send). Drop-in from 1.0.1. https://github.com/Maxofpower/FeatureFusion/blob/main/CHANGELOG.md