Mediator.Switch
1.0.0-preview1
See the version list below for details.
dotnet add package Mediator.Switch --version 1.0.0-preview1
NuGet\Install-Package Mediator.Switch -Version 1.0.0-preview1
<PackageReference Include="Mediator.Switch" Version="1.0.0-preview1" />
<PackageVersion Include="Mediator.Switch" Version="1.0.0-preview1" />
<PackageReference Include="Mediator.Switch" />
paket add Mediator.Switch --version 1.0.0-preview1
#r "nuget: Mediator.Switch, 1.0.0-preview1"
#addin nuget:?package=Mediator.Switch&version=1.0.0-preview1&prerelease
#tool nuget:?package=Mediator.Switch&version=1.0.0-preview1&prerelease
SwitchMediator
SwitchMediator: A Blazing Fast, Source-Generated Mediator for .NET
SwitchMediator provides a high-performance implementation of the mediator pattern, offering an API surface familiar to users of popular libraries like MediatR. By leveraging C# Source Generators, SwitchMediator eliminates runtime reflection for handler discovery and dispatch, instead generating highly optimized switch
statements at compile time. We also want you to Switch your Mediator to ours, get it? 😉
The result? Faster execution, improved startup times, step-into debuggability, and compile-time safety.
Table of Contents
- Why SwitchMediator?
- Key Advantages Over Reflection-Based Mediators
- Features
- Installation
- Usage Example
- License
Why SwitchMediator?
Traditional mediator implementations often rely on runtime reflection to discover handlers and construct pipelines. While flexible, this approach can introduce overhead:
- Runtime Performance Cost: Reflection and dictionary lookups add latency to every request dispatch.
- Startup Delay: Scanning assemblies and building internal mappings takes time when your application starts.
- Debugging Complexity: Stepping through the mediator logic can involve navigating complex internal library code, delegates, and reflection calls.
- Trimming/AOT Challenges: Reflection can make code less friendly to .NET trimming and Ahead-of-Time (AOT) compilation scenarios.
SwitchMediator tackles these issues head-on by moving the work to compile time. The source generator creates explicit C# code with direct handler calls and optimized switch
statements, offering a "pay-as-you-go" approach where the cost is incurred during build, not at runtime.
Key Advantages Over Reflection-Based Mediators
- 🚀 Maximum Performance: Eliminates runtime reflection and dictionary lookups for dispatch. Uses compile-time
switch
statements and direct method calls. Ideal for performance-critical paths and high-throughput applications. - 🧐 Enhanced Debuggability: You can directly step into the generated
SwitchMediator.g.cs
file! See the exactswitch
statement matching your request, observe the explicit nesting of pipeline behavior calls (await next(...)
), and step directly into your handler code. This provides unparalleled transparency compared to debugging reflection-based dispatch logic. - ✅ Compile-Time Safety: Handler discovery happens during the build. Missing request handlers result in build errors, not runtime exceptions, catching issues earlier in the development cycle.
- ⏱️ Faster Startup: Less work (like assembly scanning for handlers) needs to happen when your application boots up.
- ✂️ Trimming / AOT Friendly: Avoids runtime reflection, making the dispatch mechanism inherently more compatible with .NET trimming and AOT compilation. (Note: Ensure handlers and dependencies are also trimming/AOT safe).
- 🔍 Explicitness: The generated code serves as clear, inspectable documentation of how requests are routed and pipelines are constructed for each message type.
Features
- Request/Response messages (
IRequest<TResponse>
,IRequestHandler<TRequest, TResponse>
) - Notification messages (
INotification
,INotificationHandler<TNotification>
) - Pipeline Behaviors (
IPipelineBehavior<TRequest, TResponse>
) for cross-cutting concerns. - Flexible Pipeline Behavior Ordering via
[PipelineBehaviorOrder(int order)]
. - Pipeline Behavior Constraints using standard C# generic constraints (
where TRequest : ...
). - Explicit Notification Handler Ordering via DI configuration.
- Seamless integration with
Microsoft.Extensions.DependencyInjection
.
Installation
You'll typically need two packages:
Mediator.Switch
: Contains the core interfaces (IRequest
,INotification
,IPipelineBehavior
, etc.) and the source generator itself.Mediator.Switch.Extensions.Microsoft.DependencyInjection
: Provides extension methods for easy registration with the standard .NET DI container.
dotnet add package Mediator.Switch
dotnet add package Mediator.Switch.Extensions.Microsoft.DependencyInjection
Usage Example
This example assumes you have defined your IRequest
, INotification
, IRequestHandler
, INotificationHandler
, and IPipelineBehavior
types in your project (e.g., in the Sample
namespace and Program
's assembly).
DI Setup
Register SwitchMediator and its dependencies (handlers, behaviors, validators) in your application's composition root (e.g., Program.cs
).
using Microsoft.Extensions.DependencyInjection;
using Mediator.Switch;
using Mediator.Switch.Extensions.Microsoft.DependencyInjection;
using System;
using System.Threading.Tasks;
public static class Program
{
public static async Task Main()
{
var services = new ServiceCollection();
// --- SwitchMediator Registration ---
// 1. Register SwitchMediator itself.
// 2. Pass assembly(s) containing handlers, messages, behaviors for scanning.
services.AddScoped<SwitchMediator>(typeof(Program).Assembly)
// 3. Optionally, specify notification handler order.
.OrderNotificationHandlers<Sample.UserLoggedInEvent>(
typeof(Sample.UserLoggedInLogger),
typeof(Sample.UserLoggedInAnalytics)
);
// --- Build and Scope ---
var serviceProvider = services.BuildServiceProvider();
using var scope = serviceProvider.CreateScope(); // Simulate a request scope
var sender = scope.ServiceProvider.GetRequiredService<ISender>();
var publisher = scope.ServiceProvider.GetRequiredService<IPublisher>();
// --- Execute Logic ---
await RunSampleLogic(sender, publisher);
}
public static async Task RunSample(ISender sender, IPublisher publisher)
{
// See next section
}
}
Sending Requests & Publishing Notifications
Inject ISender
and IPublisher
into your services (controllers, etc.) and use them to dispatch messages.
// Inside the RunSampleLogic method from above
public static async Task RunSample(ISender sender, IPublisher publisher)
{
Console.WriteLine("--- Sending GetUserRequest ---");
string userResult = await sender.Send(new Sample.GetUserRequest(123));
Console.WriteLine($"--> Result: {userResult}\n");
Console.WriteLine("--- Sending CreateOrderRequest ---");
int orderResult = await sender.Send(new Sample.CreateOrderRequest("Gadget"));
Console.WriteLine($"--> Result: {orderResult}\n");
Console.WriteLine("--- Publishing UserLoggedInEvent ---");
await publisher.Publish(new Sample.UserLoggedInEvent(123));
Console.WriteLine("--- Notification Published ---\n");
Console.WriteLine("--- Sending Request with Validation Failure ---");
try
{
await sender.Send(new Sample.GetUserRequest(-1));
}
catch (FluentValidation.ValidationException ex)
{
Console.WriteLine($"--> Caught Expected ValidationException: {ex.Errors.FirstOrDefault()?.ErrorMessage}\n");
}
}
Example Output
From Sample.Program
:
--- Sending GetUserRequest ---
Logging: Handling GetUserRequest
Audit: Processing request at 27/3/2025 3:53:07 pm
Audit: Completed request at 27/3/2025 3:53:07 pm
Logging: Handled GetUserRequest
--> Result: User 123 at 27/3/2025 3:53:07 pm
--- Sending CreateOrderRequest ---
Logging: Handling CreateOrderRequest
Transaction: Starting with ID 0a12d204-8547-41e8-b6ca-d89098081ab6
Transaction: Completed with ID 0a12d204-8547-41e8-b6ca-d89098081ab6
Logging: Handled CreateOrderRequest
--> Result: 42
--- Publishing UserLoggedInEvent ---
Logged: User 123 logged in.
Analytics: User 123 tracked.
--- Notification Published ---
--- Sending GetUserRequest with Validation Failure ---
Logging: Handling GetUserRequest
--> Caught Expected ValidationException: UserId must be positive
--- Sending CreateOrderRequest with Validation Failure ---
Logging: Handling CreateOrderRequest
--> Caught Expected ValidationException: Product cannot be empty
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 was computed. 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. |
.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 was computed. 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. |
-
.NETStandard 2.0
- No dependencies.
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Mediator.Switch:
Package | Downloads |
---|---|
Mediator.Switch.Extensions.Microsoft.DependencyInjection
Microsoft Dependency Injection extensions for Mediator.Switch. |
|
Mediator.Switch.SourceGenerator
A Mediator implementation using source generated C# switch expressions for handler dispatch enabling faster execution, improved startup times, step-into debuggability, and compile-time safety. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.7.0 | 78 | 4/16/2025 |
1.6.0 | 93 | 4/14/2025 |
1.5.0 | 101 | 4/12/2025 |
1.4.0 | 135 | 4/11/2025 |
1.3.1 | 167 | 4/10/2025 |
1.3.1-preview1 | 159 | 4/10/2025 |
1.2.0 | 164 | 4/9/2025 |
1.1.0 | 161 | 3/31/2025 |
1.0.0 | 162 | 3/31/2025 |
1.0.0-preview3 | 145 | 3/30/2025 |
1.0.0-preview2 | 100 | 3/29/2025 |
1.0.0-preview1 | 138 | 3/27/2025 |