MEDIATION
MEDIATION
The crazy fast, always free MediatR alternative.
Read Me
Meditation is a lightweight, high-performance alternative to MediatR that uses Source Generation to achieve zero-reflection dispatch. By moving the logic of finding and calling handlers from runtime to compile-time, Meditation eliminates the overhead typically associated with mediator libraries, making it "super fast" and AOT-friendly.
Why Meditation?
- 🚀 Zero Reflection: No runtime assembly scanning or
MethodInfo.Invoke. Dispatching is done via source-generated pattern matching. - ⚡ Super Fast: Benchmarks (hypothetically) show near-direct method call performance.
- 🛠️ AOT Compatible: Perfect for .NET Native AOT applications because it doesn't rely on dynamic code execution.
- 🛡️ Type Safe: Compile-time validation of your requests and handlers.
- 🔌 Interceptors: Built-in support for request/response interception (similar to behaviors but simpler).
Getting Started
1. Define a Request
Requests implement IRequest (for no response) or IRequest<TResponse>.
using Meditation;
public class PingQuery : IRequest<string>
{
public string Message { get; set; }
}
2. Define a Handler
Handlers implement IHandler<TRequest, TResponse> or IHandler<TRequest>.
using Meditation;
public class PingHandler : IHandler<PingQuery, string>
{
public Task<string> HandleAsync(PingQuery request, CancellationToken ct)
{
return Task.FromResult($"Pong: {request.Message}");
}
}
3. Register Services
Since Meditation uses source generation, the Dispatcher is generated specifically for your handlers. You just need to register your handlers and the generated Dispatcher.
// In your Program.cs or Startup.cs
builder.Services.AddScoped<PingHandler>();
builder.Services.AddScoped<IDispatcher, Dispatcher>();
4. Dispatch a Request
Inject IDispatcher and send your request.
app.MapGet("/ping", async (IDispatcher dispatcher) =>
{
var response = await dispatcher.Dispatch(new PingQuery { Message = "Hello" });
return Results.Ok(response);
});
Interceptors
You can add cross-cutting concerns by implementing IInterceptor.
public class LoggingInterceptor : IInterceptor
{
public Task OnRequestAsync(object request)
{
Console.WriteLine($"Handling {request.GetType().Name}");
return Task.CompletedTask;
}
public Task OnResponseAsync(object request, object? response)
{
Console.WriteLine($"Finished {request.GetType().Name}");
return Task.CompletedTask;
}
}
// Register it
builder.Services.AddScoped<IInterceptor, LoggingInterceptor>();
How it Works
Meditation includes an Incremental Source Generator that scans your project for classes implementing IHandler. It then generates a Dispatcher class that contains a large switch statement (pattern matching).
When you call dispatcher.Dispatch(request), it matches the request object against known types and calls the appropriate handler directly. No reflection, no dictionaries, no overhead.
// Example of generated code:
public async Task<TResponse> Dispatch<TResponse>(IRequest<TResponse> request, CancellationToken ct)
{
var result = await (request switch
{
PingQuery typed => (Task<TResponse>)(object)_pingHandler.HandleAsync(typed, ct),
_ => throw new InvalidOperationException(...)
});
return result;
}
Installation
Add the following projects to your solution:
Meditation.Abstractions: Contains the interfaces.Meditation: The Source Generator project.