BuildingBlocks.Mediator 1.1.0

dotnet add package BuildingBlocks.Mediator --version 1.1.0
                    
NuGet\Install-Package BuildingBlocks.Mediator -Version 1.1.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="BuildingBlocks.Mediator" Version="1.1.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="BuildingBlocks.Mediator" Version="1.1.0" />
                    
Directory.Packages.props
<PackageReference Include="BuildingBlocks.Mediator" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add BuildingBlocks.Mediator --version 1.1.0
                    
#r "nuget: BuildingBlocks.Mediator, 1.1.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package BuildingBlocks.Mediator@1.1.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=BuildingBlocks.Mediator&version=1.1.0
                    
Install as a Cake Addin
#tool nuget:?package=BuildingBlocks.Mediator&version=1.1.0
                    
Install as a Cake Tool

BuildingBlocks.Mediator

CQRS-first Send + ordered pipeline for .NET 8+. Commands and queries, host-owned behaviors, optional traces and metrics, startup handler checks.

NuGet .NET License: MIT

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 / AddOpenQueryBehavior fail fast when the type is unconstrained
  • Opt-in Send metrics on UseTelemetry() (histogram mediator.send.duration, counter mediator.send)
  • Drop-in from 1.0.1 (CommandPipelineBehavior / QueryPipelineBehavior unchanged)

Features

  • CQRS markers: ICommand / ICommand<T> / IQuery<T> (no non-generic IQuery)
  • 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 / QueryPipelineBehavior skip 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 — histogram mediator.send.duration (ms), counter mediator.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 MakeGenericType wrappers)
  • 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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.0 65 8/27/2026
1.0.1 98 8/10/2026
1.0.0 330 8/10/2026

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