SwiftMediator 2026.4.3
dotnet add package SwiftMediator --version 2026.4.3
NuGet\Install-Package SwiftMediator -Version 2026.4.3
<PackageReference Include="SwiftMediator" Version="2026.4.3" />
<PackageVersion Include="SwiftMediator" Version="2026.4.3" />
<PackageReference Include="SwiftMediator" />
paket add SwiftMediator --version 2026.4.3
#r "nuget: SwiftMediator, 2026.4.3"
#:package SwiftMediator@2026.4.3
#addin nuget:?package=SwiftMediator&version=2026.4.3
#tool nuget:?package=SwiftMediator&version=2026.4.3
SwiftMediator
High-performance, source-generated mediator pattern for .NET — a drop-in replacement for MediatR with compile-time dispatch, zero-allocation fast paths, and full AOT/Trim compatibility.
Why SwiftMediator?
| MediatR | SwiftMediator | |
|---|---|---|
| Dispatch | Runtime reflection + Dictionary<Type> |
Compile-time switch (source-generated) |
| Return type | Task<T> |
ValueTask<T> (zero alloc for sync) |
| No-behavior path | Allocates pipeline | Fast-path — direct call, zero overhead |
| AOT / Trim | Not compatible | Fully compatible (net8.0+) |
| Error detection | Runtime exceptions | Compile-time diagnostics |
| Frameworks | net8.0, netstandard2.0 | net10.0, net8.0, netstandard2.0, net462 |
| License | Paid license key required | MIT — free forever |
Full MediatR feature parity — 20/20 features including polymorphic notifications.
Installation
dotnet add package SwiftMediator
For shared/API projects that only need marker interfaces:
dotnet add package SwiftMediator.Contracts
Quick Start
1. Define a Request and Handler
using SwiftMediator.Core;
public record PongResponse(string Reply);
public class PingRequest : IRequest<PongResponse>
{
public string Message { get; init; } = "";
}
public class PingHandler : IRequestHandler<PingRequest, PongResponse>
{
public ValueTask<PongResponse> Handle(PingRequest request, CancellationToken ct)
{
return new ValueTask<PongResponse>(new PongResponse($"Pong: {request.Message}"));
}
}
2. Register and Use
var services = new ServiceCollection();
services.AddSwiftMediator(cfg =>
{
cfg.RegisterServicesFromAssemblyContaining<Program>();
});
var provider = services.BuildServiceProvider();
var mediator = provider.GetRequiredService<IMediator>();
var response = await mediator.SendAsync<PingRequest, PongResponse>(
new PingRequest { Message = "Hello!" });
// response.Reply == "Pong: Hello!"
Examples
| Sample | Description |
|---|---|
| BasicUsage | Request/response, void commands, notifications, streaming, dynamic dispatch |
| CqrsWithValidation | CQRS pattern with commands, queries, validation pipeline, domain events |
| AdvancedPipeline | Full pipeline behaviors, exception handling, polymorphic notifications, stream pipeline, custom publisher |
Features
Void (Unit) Requests
public class DeleteUserCommand : IRequest
{
public int UserId { get; init; }
}
public class DeleteUserHandler : IRequestHandler<DeleteUserCommand, Unit>
{
public ValueTask<Unit> Handle(DeleteUserCommand request, CancellationToken ct)
{
// perform deletion
return new ValueTask<Unit>(Unit.Value);
}
}
// Convenience — no need to specify Unit:
await mediator.SendAsync(new DeleteUserCommand { UserId = 42 });
Notifications (Pub/Sub)
public class OrderCreatedEvent : INotification
{
public int OrderId { get; init; }
}
public class EmailHandler : INotificationHandler<OrderCreatedEvent>
{
public ValueTask Handle(OrderCreatedEvent notification, CancellationToken ct)
{
// send email
return default;
}
}
// Publish strategies:
await mediator.PublishAsync(evt, PublishStrategy.Sequential); // one by one (default)
await mediator.PublishAsync(evt, PublishStrategy.Parallel); // Task.WhenAll
await mediator.PublishAsync(evt, PublishStrategy.FireAndForget); // fire & forget
Polymorphic Notifications
Handlers registered for a base type/interface are invoked for all derived types:
public interface IOrderEvent : INotification { }
public class OrderConfirmedEvent : IOrderEvent { }
public class OrderCancelledEvent : IOrderEvent { }
// Runs for ALL IOrderEvent types:
public class AuditHandler : INotificationHandler<IOrderEvent> { ... }
// Runs only for OrderConfirmedEvent:
public class ConfirmedHandler : INotificationHandler<OrderConfirmedEvent> { ... }
Streaming (IAsyncEnumerable)
public class SearchQuery : IStreamRequest<SearchResult>
{
public string Term { get; init; } = "";
}
public class SearchHandler : IStreamRequestHandler<SearchQuery, SearchResult>
{
public async IAsyncEnumerable<SearchResult> Handle(
SearchQuery request, [EnumeratorCancellation] CancellationToken ct)
{
await foreach (var item in db.SearchAsync(request.Term))
yield return item;
}
}
await foreach (var result in mediator.CreateStream<SearchQuery, SearchResult>(query))
Console.WriteLine(result);
Pipeline Behaviors (Middleware)
public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
where TRequest : notnull
{
public async ValueTask<TResponse> Handle(
TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken ct)
{
Console.WriteLine($"Handling {typeof(TRequest).Name}");
var response = await next();
Console.WriteLine($"Handled {typeof(TRequest).Name}");
return response;
}
}
Fast-path: When no behaviors are registered, the handler is called directly — zero overhead.
Pre/Post Processors
public class ValidationPreProcessor<TRequest> : IRequestPreProcessor<TRequest>
where TRequest : notnull
{
public ValueTask Process(TRequest request, CancellationToken ct) { /* validate */ return default; }
}
public class AuditPostProcessor<TReq, TRes> : IRequestPostProcessor<TReq, TRes>
where TReq : notnull
{
public ValueTask Process(TReq request, TRes response, CancellationToken ct) { /* audit */ return default; }
}
Execution order: PreProcessor → Behavior(s) → Handler → PostProcessor
Exception Pipeline
// Actions — observe only (logging, metrics), cannot suppress
public class MetricsAction<TReq> : IRequestExceptionAction<TReq, Exception>
where TReq : notnull
{
public ValueTask Execute(TReq request, Exception ex, CancellationToken ct)
{
// record metrics
return default;
}
}
// Handlers — can suppress exception and return fallback
public class FallbackHandler : IRequestExceptionHandler<MyRequest, MyResponse, InvalidOperationException>
{
public ValueTask Handle(MyRequest req, InvalidOperationException ex,
RequestExceptionHandlerState<MyResponse> state, CancellationToken ct)
{
state.SetHandled(new MyResponse { /* fallback */ });
return default;
}
}
Order: Actions run first (always), then Handlers (can suppress via SetHandled()).
Stream Pipeline Behaviors
public class StreamLogging<TReq, TRes> : IStreamPipelineBehavior<TReq, TRes>
where TReq : IStreamRequest<TRes>
{
public async IAsyncEnumerable<TRes> Handle(
TReq request, StreamHandlerDelegate<TRes> next,
[EnumeratorCancellation] CancellationToken ct)
{
Console.WriteLine("Stream starting");
await foreach (var item in next())
yield return item;
Console.WriteLine("Stream completed");
}
}
Custom Notification Publisher
public class BatchPublisher : INotificationPublisher
{
public async ValueTask Publish(
IEnumerable<NotificationHandlerExecutor> executors,
INotification notification, CancellationToken ct)
{
foreach (var executor in executors)
await executor.HandlerCallback(notification, ct);
}
}
Built-in: ForeachAwaitPublisher, TaskWhenAllPublisher, FireAndForgetPublisher.
ISender / IPublisher Segregation
// Depend on the narrowest interface:
public class MyService(ISender sender) { } // can only send requests
public class MyPub(IPublisher publisher) { } // can only publish notifications
All three (IMediator, ISender, IPublisher) resolve to the same instance.
DI Configuration
Fluent API
services.AddSwiftMediator(cfg =>
{
// Lifetime
cfg.Lifetime = HandlerLifetime.Scoped; // handlers (default: Transient)
cfg.MediatorLifetime = HandlerLifetime.Singleton; // mediator (default: Scoped)
// Assembly scanning — auto-discovers behaviors, processors, exception handlers
cfg.RegisterServicesFromAssemblyContaining<Program>();
// Or register explicitly:
cfg.AddOpenBehavior(typeof(LoggingBehavior<,>))
.AddOpenBehavior(typeof(ValidationBehavior<,>))
.AddRequestPreProcessor<AuditPreProcessor>()
.AddRequestPostProcessor<CachePostProcessor>()
.AddExceptionHandler<FallbackExceptionHandler>()
.AddExceptionAction<MetricsAction>()
.AddStreamBehavior<StreamLoggingBehavior>()
.SetNotificationPublisher<TaskWhenAllPublisher>();
});
Assembly Scanning Discovers
IPipelineBehavior<,>/IStreamPipelineBehavior<,>IRequestPreProcessor<>/IRequestPostProcessor<,>IRequestExceptionHandler<,,>/IRequestExceptionAction<,>
Handlers (
IRequestHandler,INotificationHandler,IStreamRequestHandler) are discovered at compile time by the source generator — not by assembly scanning.
Compile-Time Diagnostics
| ID | Severity | Description |
|---|---|---|
SWIFT001 |
Error | Duplicate request handler |
SWIFT002 |
Error | Duplicate stream handler |
SWIFT003 |
Warning | No handlers found |
SWIFT004 |
Info | Open generic handler registered |
Supported Frameworks
| Package | Targets |
|---|---|
SwiftMediator |
net10.0, net8.0, netstandard2.0, net462 |
SwiftMediator.Contracts |
netstandard2.0 |
AOT and trim compatible on net8.0+.
Feature List
- Request/Response (
IRequest<T>→IRequestHandler<T, R>) - Void requests (
IRequest→Unit) - Notifications (
INotification→INotificationHandler<T>) - Polymorphic notifications (base type handlers invoked for derived types)
- Streaming (
IStreamRequest<T>→IAsyncEnumerable<T>) - Pipeline behaviors (
IPipelineBehavior<T, R>) - Stream pipeline behaviors (
IStreamPipelineBehavior<T, R>) - Pre/Post processors
- Exception handlers (suppress + fallback)
- Exception actions (observe only)
- Custom notification publisher (
INotificationPublisher) - ISender / IPublisher interface segregation
- Fluent DI configuration
- Assembly scanning
- Open generic handler support
- Polymorphic request dispatch
- Dynamic dispatch (
SendAsync(object)) - Handler lifetime configuration (Transient / Scoped / Singleton)
- Compile-time diagnostics
- Multi-framework support (net10.0, net8.0, netstandard2.0, net462)
Migrating from MediatR
SwiftMediator uses the same API patterns as MediatR — migration is straightforward:
| MediatR | SwiftMediator |
|---|---|
services.AddMediatR(cfg => ...) |
services.AddSwiftMediator(cfg => ...) |
cfg.RegisterServicesFromAssemblyContaining<T>() |
Same |
cfg.AddOpenBehavior(typeof(T<,>)) |
Same |
cfg.AddRequestPreProcessor<T>() |
Same |
cfg.AddRequestPostProcessor<T>() |
Same |
cfg.AddStreamBehavior<T>() |
Same |
IRequestHandler<TReq, TRes> returns Task<T> |
Returns ValueTask<T> |
cfg.LicenseKey = "..." |
Not needed — MIT licensed |
Note: MediatR now requires a paid license key. SwiftMediator is and will remain free and open source under the MIT license.
Support
If you find SwiftMediator useful, consider buying me a coffee:
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. 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 was computed. 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. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 is compatible. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETFramework 4.6.2
- Microsoft.Bcl.AsyncInterfaces (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- SwiftMediator.Contracts (>= 2026.4.3)
-
.NETStandard 2.0
- Microsoft.Bcl.AsyncInterfaces (>= 8.0.0)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- SwiftMediator.Contracts (>= 2026.4.3)
-
net10.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- SwiftMediator.Contracts (>= 2026.4.3)
-
net8.0
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 8.0.0)
- SwiftMediator.Contracts (>= 2026.4.3)
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 |
|---|---|---|
| 2026.4.3 | 73 | 4/13/2026 |