SwartBerg.Mediator
1.0.0
Make use of the latest version. Tested with .net 8, .net 9 and .net 10
See the version list below for details.
dotnet add package SwartBerg.Mediator --version 1.0.0
NuGet\Install-Package SwartBerg.Mediator -Version 1.0.0
<PackageReference Include="SwartBerg.Mediator" Version="1.0.0" />
<PackageVersion Include="SwartBerg.Mediator" Version="1.0.0" />
<PackageReference Include="SwartBerg.Mediator" />
paket add SwartBerg.Mediator --version 1.0.0
#r "nuget: SwartBerg.Mediator, 1.0.0"
#:package SwartBerg.Mediator@1.0.0
#addin nuget:?package=SwartBerg.Mediator&version=1.0.0
#tool nuget:?package=SwartBerg.Mediator&version=1.0.0
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.
Features
- High Performance: Uses expression trees and caching to avoid reflection overhead
- Background Processing: Handles notifications in the background without blocking your app
- Pipeline Behaviors: Add logging, validation, and other cross-cutting concerns easily
- Configurable Persistence: File-based persistence with JSON serialization (can be replaced)
- Retry Logic: Automatically retries failed notifications with exponential backoff
- Lightweight: Minimal dependencies, optimized for performance
- .NET 9 Ready: Takes advantage of .NET 9 performance improvements
Requirements
- .NET 9.0 or later
- Works with:
- .NET 9+ applications
- .NET MAUI applications
- Blazor applications
- ASP.NET Core 9+ applications
- Console 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
Add cross-cutting concerns like validation, logging, or caching:
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
By default, the mediator uses file-based persistence for crash recovery. The channel handles processing for high throughput.
Replace with custom persistence:
services.AddSingleton<INotificationPersistence, RedisNotificationPersistence>();
services.AddSingleton<INotificationPersistence, SqlServerNotificationPersistence>();
services.AddMediator(options => options.EnablePersistence = false, typeof(Program).Assembly);
Example Redis implementation:
public class RedisNotificationPersistence : INotificationPersistence
{
private readonly IDatabase _database;
public RedisNotificationPersistence(IConnectionMultiplexer redis)
{
_database = redis.GetDatabase();
}
public async Task<string> PersistAsync(NotificationWorkItem workItem, CancellationToken cancellationToken = default)
{
var id = Guid.NewGuid().ToString();
var persistedItem = new PersistedNotificationWorkItem
{
Id = id,
WorkItem = workItem,
CreatedAt = DateTime.UtcNow,
AttemptCount = 0
};
var key = $"mediator:notifications:{id}";
var value = JsonSerializer.Serialize(persistedItem);
await _database.StringSetAsync(key, value);
return id;
}
// implement other interface methods
}
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);
}, typeof(Program).Assembly);
Architecture
The mediator uses a channel-first approach with optional persistence backup:
- Primary Processing: In-memory channels for fast, reliable processing
- Persistence: Optional backup that saves notifications to disk/storage
- Recovery: On startup/timer, recovers persisted notifications back into the channel
- Cleanup: Removes old persisted items periodically
Flow:
Publish() → Channel (immediate) → Background Workers
↓
Persist() (async backup) → Storage
↓
Recovery Timer → Load from Storage → Back to Channel
Performance Benchmarks
BenchmarkDotNet results on .NET 9 (Intel Core i7-13620H):
Request Processing
| Method | Mean | Error | StdDev | Allocated | Throughput |
|---|---|---|---|---|---|
| SingleRequest | 98.05 ns | 1.94 ns | 1.81 ns | 672 B | ~10.2M req/sec |
| BatchRequests100 | 9.70 μs | 0.17 μs | 0.16 μs | 64 KB | ~103K batches/sec |
Notification Processing
| Method | Mean | Error | StdDev | Allocated | Throughput |
|---|---|---|---|---|---|
| SingleNotification | 348.2 ns | 3.45 ns | 3.23 ns | 717 B | ~2.9M notifs/sec |
| BatchNotifications100 | 40.18 μs | 0.48 μs | 0.40 μs | 80 KB | ~24.9K batches/sec |
Performance Highlights
- Blazing requests: 98ns per request - one of the fastest mediators available
- Ultra-fast notifications: 348ns with background processing
- Outstanding throughput: 10.2 million requests per second capability
- Efficient batch processing: 100 requests in 9.7μs
- Low memory usage: Optimized allocations with compiled delegates
- Pipeline behavior support: Full hot path optimization for behaviors too
- Enterprise-grade performance: Perfect for hyperscale production systems
Run benchmarks:
cd benchmarks
dotnet run -c Release
Testing
dotnet test
cd benchmarks
dotnet run -c Release
Contributing
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes and add tests
- Run benchmarks to ensure performance
- Commit your changes:
git commit -m 'Add amazing feature' - Push to the branch:
git push origin feature/amazing-feature - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
- Create an issue for bug reports or feature requests
- Check existing issues before creating new ones
- Provide clear reproduction steps for bugs
Appreciation (Optional)
SwartBerg.Mediator is completely free and always will be. Use it, modify it, distribute it - no strings attached!
If this library happens to save you time or makes your project better, and you feel like buying me a coffee out of the goodness of your heart, that's awesome but totally optional:
Remember: This library will always be free, regardless of donations. No premium features, no paid support, no strings attached.
Contributors
Thanks to all the developers who contribute to making SwartBerg.Mediator better!
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | 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 was computed. 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. |
-
net9.0
- Microsoft.CSharp (>= 4.7.0)
- Microsoft.Extensions.DependencyInjection (>= 9.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.0)
- Microsoft.Extensions.Logging (>= 9.0.0)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.0)
- Microsoft.Extensions.Options (>= 9.0.0)
- System.Text.Json (>= 9.0.0)
- System.Threading.Channels (>= 9.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 | |
|---|---|---|---|
| 3.1.0 | 51 | 10/3/2026 | |
| 3.0.0 | 65 | 10/2/2026 | |
| 2.0.12 | 1,300 | 4/1/2026 | |
| 2.0.11 | 131 | 3/31/2026 | |
| 2.0.10 | 307 | 2/19/2026 | |
| 2.0.9 | 147 | 2/18/2026 | |
| 2.0.8 | 218 | 2/12/2026 | |
| 2.0.7 | 171 | 2/7/2026 | |
| 2.0.6 | 188 | 2/1/2026 | |
| 2.0.5 | 156 | 2/1/2026 | |
| 2.0.4 | 153 | 1/31/2026 | |
| 2.0.3 | 158 | 1/28/2026 | |
| 2.0.2 | 185 | 1/23/2026 | |
| 2.0.1 | 156 | 1/22/2026 | |
| 2.0.0 | 211 | 1/9/2026 | |
| 1.0.5 | 378 | 11/24/2025 | |
| 1.0.4 | 473 | 11/20/2025 | |
| 1.0.3 | 470 | 11/19/2025 | |
| 1.0.2 | 462 | 11/19/2025 | |
| 1.0.0 | 291 | 9/20/2025 |
High-performance .NET 9 mediator with compiled expressions, background notifications, pipeline behaviors, and file-based persistence with retry logic.