How to Implement Mediator Pattern in .NET
By FoxLearn 2/21/2025 7:18:34 AM 26
This article demonstrates how to reduce this complexity using the Mediator pattern and how to implement it in a .NET Web API.
The Real-Time Problem
Let’s take a real-time example of a product ordering system. Suppose we have the following components:
- Order Component
- Payment Component
- Inventory Component
- Notification Component
These components need to interact. For example, when an order is placed, the Order Component might need to communicate with the Payment Component to process the payment, the Inventory Component to check stock, and the Notification Component to send confirmation emails. If each component directly communicates with others, the system quickly becomes tightly coupled and difficult to manage, especially when the number of components increases.
Reducing Coupling with the Mediator Pattern
The Mediator Pattern is a behavioral design pattern that centralizes communication between components through a mediator object, reducing the direct dependencies between components. Instead of components communicating directly with each other, they communicate via the mediator, which delegates the message to the appropriate recipient.
Let’s consider our product ordering system again and redesign it using the Mediator pattern.
Real-World Example: Order Processing System
Imagine an OrderProcessing system in which we have various components:
- Order Component
- Payment Component
- Inventory Component
- Notification Component
Each component should communicate through a mediator rather than directly with one another.
Components Involved in the Mediator Pattern
- Component: These are the individual classes with business logic, each referring to the mediator.
- Mediator: The mediator interface defines communication methods for all components.
- Concrete Mediator: This manages interactions between the components.
Example Code Implementation:
Step 1: Define the Mediator Interface
public interface IOrderMediator { void ProcessOrder(string orderDetails); void RegisterComponent(IOrderComponent component); }
Step 2: Define the Order Component Interface
public interface IOrderComponent { void Execute(string orderDetails); }
Step 3: Concrete Order Components
public class PaymentComponent : IOrderComponent { private readonly IOrderMediator _mediator; public PaymentComponent(IOrderMediator mediator) { _mediator = mediator; } public void Execute(string orderDetails) { Console.WriteLine($"Processing payment for order: {orderDetails}"); } } public class InventoryComponent : IOrderComponent { private readonly IOrderMediator _mediator; public InventoryComponent(IOrderMediator mediator) { _mediator = mediator; } public void Execute(string orderDetails) { Console.WriteLine($"Checking inventory for order: {orderDetails}"); } } public class NotificationComponent : IOrderComponent { private readonly IOrderMediator _mediator; public NotificationComponent(IOrderMediator mediator) { _mediator = mediator; } public void Execute(string orderDetails) { Console.WriteLine($"Sending order confirmation for order: {orderDetails}"); } }
Step 4: Implement the Concrete Mediator
public class OrderMediator : IOrderMediator { private readonly List<IOrderComponent> _components; public OrderMediator() { _components = new List<IOrderComponent>(); } public void RegisterComponent(IOrderComponent component) { _components.Add(component); } public void ProcessOrder(string orderDetails) { foreach (var component in _components) { component.Execute(orderDetails); } } }
Step 5: Main Program for Mediator Interaction
class Program { static void Main(string[] args) { var mediator = new OrderMediator(); var payment = new PaymentComponent(mediator); var inventory = new InventoryComponent(mediator); var notification = new NotificationComponent(mediator); mediator.RegisterComponent(payment); mediator.RegisterComponent(inventory); mediator.RegisterComponent(notification); // Process an order mediator.ProcessOrder("Order #12345"); Console.ReadKey(); } }
How the Mediator Pattern Solves the Problem
In this setup, each component (Payment, Inventory, and Notification) communicates through the OrderMediator
. Instead of calling each other directly, the components rely on the mediator to handle communication and actions, making the system easier to maintain and extend.
Implementing Mediator Pattern in .NET Web API
The MediatR library provides a convenient way to implement the Mediator pattern in .NET applications, allowing communication between objects without tight coupling.
Step 1: Install MediatR Package
To get started, install the MediatR package using NuGet:
Install-Package MediatR Install-Package MediatR.Extensions.Microsoft.DependencyInjection
Step 2: Define the Request and Response Models
For example, to process an order:
public class ProcessOrderCommand : IRequest<string> { public string OrderDetails { get; set; } }
Step 3: Create the Command Handler
public class ProcessOrderHandler : IRequestHandler<ProcessOrderCommand, string> { public Task<string> Handle(ProcessOrderCommand request, CancellationToken cancellationToken) { // Logic to process the order string response = $"Order processed: {request.OrderDetails}"; return Task.FromResult(response); } }
Step 4: Configure MediatR in the Startup
public class Startup { public void ConfigureServices(IServiceCollection services) { services.AddMediatR(typeof(Startup).Assembly); } }
Step 5: Create the API Controller
public class OrderController : ControllerBase { private readonly IMediator _mediator; public OrderController(IMediator mediator) { _mediator = mediator; } [HttpPost("process-order")] public async Task<IActionResult> ProcessOrder([FromBody] ProcessOrderCommand command) { string result = await _mediator.Send(command); return Ok(result); } }
Flow of the Process
- A POST request is made to the
process-order
endpoint with the order details. - The
ProcessOrderCommand
is sent via MediatR. - MediatR locates the appropriate handler (
ProcessOrderHandler
) to process the command. - The handler returns a response (e.g., "Order processed: Order #12345").
- The controller sends the response back to the client.
In this article, we’ve explored the Mediator pattern, how it helps reduce tight coupling between components, and how to implement it in a .NET Web API. By using MediatR, we can streamline communication between objects and create more modular, maintainable code.
- Options Pattern In ASP.NET Core
- Implementing Rate Limiting in .NET
- IExceptionFilter in .NET Core
- Repository Pattern in .NET Core
- CRUD with Dapper in ASP.NET Core
- How to use AutoMapper in ASP.NET Core
- How to fix 'asp-controller and asp-action attributes not working in areas'
- Basic Authentication in ASP.NET Core