SwartBerg.Mediator
2.0.2
See the version list below for details.
dotnet add package SwartBerg.Mediator --version 2.0.2
NuGet\Install-Package SwartBerg.Mediator -Version 2.0.2
<PackageReference Include="SwartBerg.Mediator" Version="2.0.2" />
<PackageVersion Include="SwartBerg.Mediator" Version="2.0.2" />
<PackageReference Include="SwartBerg.Mediator" />
paket add SwartBerg.Mediator --version 2.0.2
#r "nuget: SwartBerg.Mediator, 2.0.2"
#:package SwartBerg.Mediator@2.0.2
#addin nuget:?package=SwartBerg.Mediator&version=2.0.2
#tool nuget:?package=SwartBerg.Mediator&version=2.0.2
SwartBerg.Mediator
A fast mediator implementation for .NET 9 with background processing and notification persistence.
Inspired by MediatR, this library was created as a free alternative with similar patterns but optimized for performance and includes built-in persistence and background processing.
The name "SwartBerg" means "Black Mountain" in Afrikaans, it is a combination of my surname and my wife's maiden name. If you like to thank me for the library buy me a coffee. Link is at the bottom of this readme.
Features
- High Performance: Precompiled generic delegates (no runtime expression compilation)
- Background Processing: Non-blocking notification dispatch with worker pool
- Pipeline Behaviors: Plug-in cross-cutting concerns
- Configurable Persistence: Pluggable store & serializer
- Retry Logic: Exponential backoff with precomputed delays
- Modern Async Patterns: Optional global ConfigureAwait(false)
- Lightweight: Low allocations, minimal deps
- .NET 9 Ready: Utilizes latest runtime improvements
Requirements
- .NET 9.0 or later
- Works with:
- .NET 9+ applications
- .NET MAUI applications
- Blazor applications
- ASP.NET Core 9+ applications
- Console applications
- WPF applications
- WinForms applications
Installation
Package Manager Console
Install-Package SwartBerg.Mediator
.NET CLI
dotnet add package SwartBerg.Mediator
PackageReference
<PackageReference Include="SwartBerg.Mediator" Version="1.0.0" />
Quick Start
1. Define your requests and handlers
public class GetUserQuery : IRequest<User>
{
public int UserId { get; set; }
}
public class GetUserHandler : IRequestHandler<GetUserQuery, User>
{
public Task<User> Handle(GetUserQuery request, CancellationToken cancellationToken)
{
return Task.FromResult(new User { Id = request.UserId, Name = "John Doe" });
}
}
public class CreateUserCommand : IRequest
{
public string Name { get; set; }
public string Email { get; set; }
}
public class CreateUserHandler : IRequestHandler<CreateUserCommand>
{
public Task Handle(CreateUserCommand request, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
public class UserCreatedNotification : INotification
{
public int UserId { get; set; }
public string Name { get; set; }
}
public class SendWelcomeEmailHandler : INotificationHandler<UserCreatedNotification>
{
public Task Handle(UserCreatedNotification notification, CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
}
2. Register services
builder.Services.AddMediator(typeof(Program).Assembly);
3. Use the mediator
public class UserController : ControllerBase
{
private readonly IMediator _mediator;
public UserController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet("{id}")]
public async Task<User> GetUser(int id)
{
return await _mediator.Send(new GetUserQuery { UserId = id });
}
[HttpPost]
public async Task CreateUser(CreateUserCommand command)
{
await _mediator.Send(command);
await _mediator.Publish(new UserCreatedNotification { UserId = 1, Name = command.Name });
}
}
Advanced Configuration
Pipeline Behaviors
public class ValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : IRequest<TResponse>
{
public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
ValidateRequest(request);
return await next();
}
}
services.AddTransient(typeof(IPipelineBehavior<,>), typeof(ValidationBehavior<,>));
Custom Persistence
services.AddSingleton<INotificationPersistence, RedisNotificationPersistence>();
services.AddSingleton<INotificationPersistence, SqlServerNotificationPersistence>();
services.AddMediator(options => options.EnablePersistence = false, typeof(Program).Assembly);
Configuration Options
services.AddMediator(options =>
{
options.NotificationWorkerCount = 4;
options.EnablePersistence = true;
options.ProcessingInterval = TimeSpan.FromSeconds(30);
options.ProcessingBatchSize = 50;
options.MaxRetryAttempts = 3;
options.InitialRetryDelay = TimeSpan.FromMinutes(2);
options.RetryDelayMultiplier = 2.0;
options.CleanupRetentionPeriod = TimeSpan.FromHours(24);
options.CleanupInterval = TimeSpan.FromHours(1);
// options.UseConfigureAwaitGlobally = false; // only if you need sync ctx
}, typeof(Program).Assembly);
Architecture
Channel-first with optional persistence:
- In-memory channel dispatch
- Optional persistence backup
- Periodic recovery loop
- Periodic cleanup loop
Publish() → Channel → Background Workers
↘
Persist() → Storage
↘
Recovery → Channel
Performance Benchmarks
Latest request benchmark excerpt (.NET 9.0.11, Intel i7-13620H, single run):
| Method | Mean (ns) | Allocated (B) | Approx Throughput (ops/sec) |
|---|---|---|---|
| SimpleRequestResponse | 94.66 | 672 | ~10.56 M |
| ComplexRequestResponse | 120.36 | 688 | ~8.31 M |
| SimpleRequestWithoutResponse | 98.39 | 240 | ~10.16 M |
| RequestWith1000Iterations* | 103.45 | 644 | ~9.66 M (avg/op) |
*Batch of 1000 requests total ≈103,448 ns (≈103.45 ns each).
Latest notification benchmark excerpt (.NET 9.0.11, Intel i7-13620H, single run):
| Method | Mean (ms) | Allocated (B) |
|---|---|---|
| PublishSimpleNotification | 15.85 | 950 |
| PublishComplexNotification | 16.00 | 936 |
| Publish100Notifications | 56.09 | 27,261 |
| Publish1000Notifications | 105.54 | 270,549 |
Notes:
- Notification benchmarks include enqueue + background processing overhead.
- Allocation scales primarily with handler count and batch size.
- Single notification latency dominated by worker scheduling (intentionally decoupled).
Highlights
- Precompiled delegates
- Immutable work item struct
- Pooled task arrays for multi-handler fan-out
- Fast-path synchronous completions
- Exponential retry with precomputed delays
Numbers from a single run; re-run on your hardware for authoritative results.
Run benchmarks:
cd benchmarks
DOTNET_TieredPGO=1 DOTNET_ReadyToRun=0 dotnet run -c Release --filter *Request*
DOTNET_TieredPGO=1 DOTNET_ReadyToRun=0 dotnet run -c Release --filter *Publish*
Testing
dotnet test
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Add changes + tests
- Run benchmarks
- Commit:
git commit -m 'Add amazing feature' - Push:
git push origin feature/amazing-feature - Open PR
License
MIT License - see LICENSE.
Support
Open issues for bugs or features. Provide clear reproduction steps.
Appreciation (Optional)
Free forever. If it helps you and you want to buy a coffee:
**Always free. No premium features, no paid support.**Always free. No premium features, no paid support.
| 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.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Options (>= 8.0.0)
-
net8.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Options (>= 8.0.0)
-
net9.0
- Microsoft.Extensions.DependencyInjection (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Logging (>= 8.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 8.0.0)
- Microsoft.Extensions.Options (>= 8.0.0)
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 |
|---|---|---|
| 2.0.12 | 186 | 4/1/2026 |
| 2.0.11 | 95 | 3/31/2026 |
| 2.0.10 | 261 | 2/19/2026 |
| 2.0.9 | 98 | 2/18/2026 |
| 2.0.8 | 154 | 2/12/2026 |
| 2.0.7 | 123 | 2/7/2026 |
| 2.0.6 | 138 | 2/1/2026 |
| 2.0.5 | 107 | 2/1/2026 |
| 2.0.4 | 107 | 1/31/2026 |
| 2.0.3 | 107 | 1/28/2026 |
| 2.0.2 | 138 | 1/23/2026 |
| 2.0.1 | 108 | 1/22/2026 |
| 2.0.0 | 165 | 1/9/2026 |
| 1.0.5 | 264 | 11/24/2025 |
| 1.0.4 | 428 | 11/20/2025 |
| 1.0.3 | 423 | 11/19/2025 |
| 1.0.2 | 422 | 11/19/2025 |
| 1.0.1 | 194 | 10/31/2025 |
| 1.0.0 | 240 | 9/20/2025 |
| 0.1.4-ci0010 | 220 | 9/20/2025 |
Version 2.0.0: Added support for .NET 10. High-performance mediator with compiled expressions, background notifications, pipeline behaviors, file-based persistence with retry logic, and built-in ConfigureAwait(false) for automatic deadlock prevention. Safe by default for all application types. Supports .NET 9 and .NET 10.