Orchestrix.Mediator: A Modern Mediator Engine for .NET 8/9/10+

Orchestrix.Mediator: A Modern Mediator Engine for .NET 8/9/10+

Publish Date: Jul 20
0 0

Tired of hitting limits with MediatR?

Meet Orchestrix.Mediator — a next-gen mediator engine designed for the modern .NET ecosystem.


✨ Why Orchestrix.Mediator?

Orchestrix.Mediator isn’t just a clone of MediatR. It’s a reimagined mediator with first-class support for the features developers now expect:

✅ Zero-reflection dispatch via source generators

✅ Parallel notifications with built-in fan-out

✅ Asynchronous streaming using IAsyncEnumerable<T>

✅ Hook-based diagnostics for tracing, logging, and metrics

✅ CQRS extensions with ICommand, IQuery, and semantic handlers

✅ Minimal API & Controller support

✅ Fully ValueTask-based and AOT-safe

All while preserving the simplicity and ergonomics of MediatR.


⚙️ Quick Start

1. Install

dotnet add package Orchestrix.Mediator
Enter fullscreen mode Exit fullscreen mode

Optional extensions:

dotnet add package Orchestrix.Mediator.SourceGenerators
dotnet add package Orchestrix.Mediator.Cqrs
Enter fullscreen mode Exit fullscreen mode

2. Register in Program.cs

builder.Services.AddOrchestrix(cfg => 
{
    cfg.UseSourceGenerator() // optional: enables zero-reflection dispatch
       .RegisterHandlersFromAssemblies(typeof(MyHandler).Assembly);
});
Enter fullscreen mode Exit fullscreen mode

3. Define a Command + Handler

public record CreateUserCommand(string Name) : IRequest<Guid>;

public class CreateUserHandler : IRequestHandler<CreateUserCommand, Guid>
{
    public ValueTask<Guid> Handle(CreateUserCommand request, CancellationToken ct)
    {
        return ValueTask.FromResult(Guid.NewGuid());
    }
}
Enter fullscreen mode Exit fullscreen mode

4. Dispatch via ISender

var id = await sender.Send(new CreateUserCommand("Mohammad"));
Enter fullscreen mode Exit fullscreen mode

📢 Notifications with Fan-Out

public record UserRegistered(string Email) : INotification;

public class LogHandler : INotificationHandler<UserRegistered>
{
    public ValueTask Handle(UserRegistered n, CancellationToken ct)
        => ValueTask.CompletedTask;
}

public class EmailHandler : IParallelNotificationHandler<UserRegistered>
{
    public async ValueTask Handle(UserRegistered n, CancellationToken ct)
    {
        await Task.Delay(100);
        Console.WriteLine($"Welcome {n.Email}");
    }
}
Enter fullscreen mode Exit fullscreen mode

📣 Both handlers will run: one sequentially, the other in parallel!

await publisher.Publish(new UserRegistered("user@example.com"));
Enter fullscreen mode Exit fullscreen mode

📡 Streaming with IAsyncEnumerable<T>

public record GetUsers(int Count) : IStreamRequest<UserDto>;

public class GetUsersHandler : IStreamRequestHandler<GetUsers, UserDto>
{
    public async IAsyncEnumerable<UserDto> Handle(GetUsers req, [EnumeratorCancellation] CancellationToken ct)
    {
        for (int i = 0; i < req.Count; i++)
        {
            yield return new UserDto(Guid.NewGuid(), $"User-{i + 1}");
            await Task.Delay(100, ct);
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Dispatch:

await foreach (var user in sender.CreateStream(new GetUsers(5), ct))
{
    Console.WriteLine(user.Name);
}
Enter fullscreen mode Exit fullscreen mode

🪝 Built-in Hooks for Tracing & Logging

Orchestrix.Mediator supports lifecycle instrumentation via hooks:

  • ISendHook
  • IPublishHook
  • IStreamHook

Example:

public class LoggingHook : ISendHook
{
    public ValueTask OnSendStart(object request, CancellationToken ct)
        => Log($"[SEND] Start: {request.GetType().Name}");

    public ValueTask OnSendComplete(object request, object? response, CancellationToken ct)
        => Log($"[SEND ✅] Completed: {response}");

    public ValueTask OnSendError(object request, Exception ex, CancellationToken ct)
        => Log($"[SEND ❌] Failed: {ex.Message}");
}
Enter fullscreen mode Exit fullscreen mode

Register:

services.AddOrchestrix(cfg => cfg.AddHook<LoggingHook>());
Enter fullscreen mode Exit fullscreen mode

🧱 Pipelines Still Here

Need validation, logging, or retry logic?

public class LoggingBehavior<TReq, TRes> : IPipelineBehavior<TReq, TRes>
    where TReq : IRequest<TRes>
{
    public async ValueTask<TRes> Handle(TReq req, RequestHandlerDelegate<TRes> next, CancellationToken ct)
    {
        Console.WriteLine($"Handling {typeof(TReq).Name}");
        return await next(ct);
    }
}
Enter fullscreen mode Exit fullscreen mode

Register with:

cfg.AddOpenBehavior(typeof(LoggingBehavior<,>));
Enter fullscreen mode Exit fullscreen mode

🧭 CQRS Done Right

Install:

dotnet add package Orchestrix.Mediator.Cqrs
Enter fullscreen mode Exit fullscreen mode

Use:

public record SaveUser(string Name) : ICommand<Guid>;

public class SaveUserHandler : ICommandHandler<SaveUser, Guid>
{
    public ValueTask<Guid> Handle(SaveUser cmd, CancellationToken ct)
        => ValueTask.FromResult(Guid.NewGuid());
}
Enter fullscreen mode Exit fullscreen mode

🔁 TrySend / TryPublish

bool handled = await sender.TrySend(new OptionalCommand());

bool published = await publisher.TryPublish(new OptionalEvent());
Enter fullscreen mode Exit fullscreen mode

Avoid exceptions when no handler is found.


✨ Optional: Source Generator Boost

Install:

dotnet add package Orchestrix.Mediator.SourceGenerators
Enter fullscreen mode Exit fullscreen mode

Add:

cfg.UseSourceGenerator();
Enter fullscreen mode Exit fullscreen mode

No reflection. No runtime resolution. AOT-safe.

Orchestrix will emit a GeneratedDispatcher behind the scenes.


🧪 Fully Testable

var sender = new Mock<ISender>();
sender.Setup(s => s.Send(It.IsAny<IRequest<Guid>>(), It.IsAny<CancellationToken>()))
      .ReturnsAsync(Guid.NewGuid());
Enter fullscreen mode Exit fullscreen mode

Use ISender, IPublisher, or IMediator in your tests.


🔁 Migrating from MediatR?

✅ Use the same patterns

✅ Replace IMediator with ISender/IPublisher

✅ Update AddMediatR to AddOrchestrix

✅ Replace INotificationHandler<T> with IParallelNotificationHandler<T> if needed

Read full migration guide → MIGRATION.md


📚 Resources


🔥 Ready to Modernize Mediation?

Whether you’re building a CQRS-heavy application, orchestrating event-driven flows, or simply want better observability — Orchestrix.Mediator is built to scale with you.

👉 Give it a ⭐ on GitHub: github.com/anzawi/Orchestrix.Mediator

💬 Feedback or questions? Drop them in the repo’s issues!

Comments 0 total

    Add comment