Mediator Design Pattern in .NET Core API
A practical Mediator pattern guide in C# with centralized and hierarchical coordination styles for clean .NET workflows.

Intro
As application workflows grow, components can become tangled by calling each other directly. The Mediator pattern keeps that under control by moving communication into one coordinating object.
What Is the Mediator Pattern?
Mediator is a behavioral design pattern that centralizes communication between related objects so they do not depend on each other directly.
In .NET systems, it often appears in form workflows, dialog coordination, domain orchestration, and application services that coordinate multiple dependencies.
Mediator Class Example
The example below models an order checkout flow where the mediator coordinates inventory, payment, and confirmation steps.
public sealed record CheckoutRequest(Guid OrderId, decimal Amount);
public interface ICheckoutMediator{ Task SubmitAsync(CheckoutRequest request, CancellationToken cancellationToken);}
public sealed class CheckoutMediator( IInventoryService inventory, IPaymentService payment, INotificationService notifications) : ICheckoutMediator{ public async Task SubmitAsync(CheckoutRequest request, CancellationToken cancellationToken) { await inventory.ReserveAsync(request.OrderId, cancellationToken); await payment.ChargeAsync(request.OrderId, request.Amount, cancellationToken); await notifications.SendConfirmationAsync(request.OrderId, cancellationToken); }}Why This Works
The mediator becomes the single place where collaboration rules live. Individual services stay focused on their own behavior while the mediator owns the order in which they are invoked.
When to Use It
Mediator is a strong fit when many components need to coordinate but should not know about one another.
- coordinating multi-step form or wizard flows
- orchestrating backend application services
- reducing many-to-many object dependencies
- centralizing UI dialog or screen interactions
- keeping workflow changes out of individual services
If one object only talks to one other object, direct composition is usually simpler.
Important Note for ASP.NET Core
In ASP.NET Core, mediators are often implemented as application services or through dispatcher abstractions registered in DI. This keeps controllers thin and makes orchestration easier to test.
public interface ICommandMediator<TCommand>{ Task HandleAsync(TCommand command, CancellationToken cancellationToken);}
builder.Services.AddScoped<ICheckoutMediator, CheckoutMediator>();This arrangement helps you add validation, logging, and retries around one coordination boundary instead of scattering them across controllers.
Core Components of the Pattern
| Part | Purpose | Example in this article |
|---|---|---|
| Mediator | Coordinates collaboration | CheckoutMediator |
| Colleagues | Work through the mediator | inventory, payment, notification services |
| Request model | Carries workflow input | CheckoutRequest |
| Client | Starts the workflow | controller or API endpoint |
Common Mediator Variations
You will commonly apply the Mediator pattern in these two forms:
Centralized Mediator (Source)
A single mediator owns the full workflow and keeps all participants decoupled.
public sealed class OrderWorkflowMediator : ICheckoutMediator{ public Task SubmitAsync(CheckoutRequest request, CancellationToken cancellationToken) => Task.CompletedTask;}Hierarchical Mediator (Source)
Multiple mediators coordinate sub-flows, each responsible for one layer of the workflow.
public interface IPaymentMediator{ Task ChargeAsync(Guid orderId, decimal amount, CancellationToken cancellationToken);}How the Variations Differ
| Variation | Coordination model | Complexity | Best use case |
|---|---|---|---|
| Centralized Mediator | One object owns the full workflow | Lower | Small to medium orchestration |
| Hierarchical Mediator | Multiple mediators split responsibilities | Higher | Large workflows with clear subdomains |
SOLID Principles Behind It
SRP - Single Responsibility Principle
Colleagues focus on one responsibility while the mediator focuses on coordination.
OCP - Open/Closed Principle
You can add new steps or participants without rewriting all peers.
DIP - Dependency Inversion Principle
Participants depend on mediator abstractions instead of hard-coded collaborators.
Advantages and Disadvantages
Advantages
- reduces object-to-object coupling
- centralizes orchestration logic
- improves workflow testability
- keeps participant classes small and focused
Disadvantages (and Optional Alternatives)
- mediators can become large if they absorb too much logic Optional pattern: Facade (when the main goal is simpler access, not orchestration).
- workflow changes may require touching the mediator more often than the colleagues Optional pattern: Chain of Responsibility (when steps can independently approve or reject).
- deep coordination graphs can be harder to visualize Optional pattern: Observer (when the main need is event fan-out instead of orchestration).
UML Diagram
classDiagram class Client class ICheckoutMediator { <<interface>> +SubmitAsync(request) } class CheckoutMediator class InventoryService class PaymentService class NotificationService
Client --> ICheckoutMediator CheckoutMediator ..|> ICheckoutMediator CheckoutMediator --> InventoryService CheckoutMediator --> PaymentService CheckoutMediator --> NotificationServiceA Quick Usage Example
var request = new CheckoutRequest(Guid.NewGuid(), 250m);await checkoutMediator.SubmitAsync(request, CancellationToken.None);The caller triggers one coordination entry point while the mediator manages the collaboration details.
How to Validate the Pattern
Use these checks to confirm your Mediator implementation is healthy:
- colleagues should not call each other directly
- workflow ordering should live in the mediator, not in controllers
- each mediator should stay focused on a single coordination boundary
- tests should verify orchestration without requiring real upstream callers
- you should be able to swap a colleague without changing all peers
Is there any other way to check our implementations
- yes, add unit tests for the mediator workflow steps
- add integration tests around DI registration and endpoint execution
Summary
The Mediator pattern keeps collaborative workflows focused and maintainable by moving conversation rules into a dedicated coordinator. In .NET APIs, it is especially useful when application services need to orchestrate several dependencies without creating a web of direct references.




