The Mediator Pattern In .NET Core

A couple of years back, I had to help out on a project that was built entirely using the “Mediator Pattern”. Or more specifically, built entirely using the MediatR library. There were all these presentations about the “theory” behind the Mediator Pattern and how it was a real new way of thinking. I couldn’t help but think… We’ve been doing this for years. Except we just call it good programming… Infact I had my own pattern which we’ll look into in Part 2 that I called the “IEnumerable Pattern” which achieved the same thing.

But it’s taken all these years to finally write it all down. So here it is. Here’s the Mediator Pattern in C# (Or more specifically, .NET Core).

The Mediator Pattern “Definition”

The Mediator Pattern actually dates all the way back to 1994 in the famous book “Design Patterns: Elements of Reusable Object-Oriented Software”. But I feel like it’s only really sprung up again lately due to a slew of libraries trying to implement the pattern.

In a nutshell, the definition (as stolen from Wikipedia) is :

The essence of the Mediator Pattern is to “define an object that encapsulates how a set of objects interact”. It promotes loose coupling by keeping objects from referring to each other explicitly, and it allows their interaction to be varied independently. Client classes can use the mediator to send messages to other clients, and can receive messages from other clients via an event on the mediator class.

So let’s break it down a little into two bullet points that we will refer back to later.

  • It’s an object that encapsulates how objects interact. So it can obviously handle passing on “messages” between objects.
  • It promotes loose coupling by not having objects refer to each other, but instead to the mediator. So they pass the messages to the mediator, who will pass it on to the right person.

That’s honestly it.

And when you think about just those two bullet points in isolation. It sounds awfully like a message hub of sorts right? That’s because… It actually kinda is. It’s like a message hub in code. When you send a message through a typical message hub, you don’t know who is receiving that message, you just know that the hub knows and it will sort it out for you.

In Visual Form

If we break this out into visual form using my (very limited) lucidchart skills. It looks a bit like this :

This is probably a simplified version of it because a Mediator Pattern does allow two way communication, it’s not just a one way broadcast, but I think this is the model we are going to try and use going forward in our examples.

Again, looking at it this way, it’s hard not to see the comparisons to messaging systems. But on the other hand, it’s hard not to also feel like this could very quickly turn into one of those “super” classes where sure, MyService doesn’t reference every handler… But the Mediator does. But there are ways to handle that which we will go into later.

Why?

And finally, the “Why?”. Why is this even a thing?

Well if we take the diagram above, if we had MyService calling other handlers directly (For example notifying them about an action), then as we add handlers, MyService has to start referencing them all even if it doesn’t care about the result. For example, our service might start looking like this :

class MyService
{
    private readonly Handler1 _handler1;
    private readonly Handler2 _handler2;
    private readonly Handler3 _handler3;
            
 
    public MyService(Handler1 handler1, Handler2 handler2, Handler3 handler3)
    {
        _handler1 = handler1;
        _handler2 = handler2;
        _handler3 = handler3;
    }
 
    public void DoSomething()
    {
        //Do something here. 
        //And do some more work
 
        //And then notify our handlers. 
        _handler1.Notify(new HandlerArgs());
        _handler2.Notify(new HandlerArgs());
        _handler3.Notify(new HandlerArgs());
    }
}

So what happens when we add more handlers? Or remove handlers? Our service keeps changing when in reality it doesn’t really care who gets notified.

Using a Mediator Pattern, it may instead end up looking like :

class MyService
{
    private HandlerMediator _handlerMediator;
 
    public MyService(HandlerMediator handlerMediator)
    {
        _handlerMediator = handlerMediator;
    }
 
    public void DoSomething()
    {
        //Do something here. 
        //And do some more work
 
        //And then notify our handlers. 
        _handlerMediator.Notify(new HandlerArgs());
    }
}
 
 
class HandlerMediator
{
    private readonly Handler1 _handler1;
    private readonly Handler2 _handler2;
    private readonly Handler3 _handler3;
 
 
    public HandlerMediator(Handler1 handler1, Handler2 handler2, Handler3 handler3)
    {
        _handler1 = handler1;
        _handler2 = handler2;
        _handler3 = handler3;
    }
 
    public void Notify(HandlerArgs handlerArgs)
    {
        _handler1.Notify(handlerArgs);
        _handler2.Notify(handlerArgs);
        _handler3.Notify(handlerArgs);
    }
}

So there’s the bonus that as handlers change, get added or removed, the service itself doesn’t change. But there is also a bit of a downer that we are maybe shifting the load to the Mediator, it’s job is now to manage the handlers and how they get notified. But this makes sense right! To have a class whose sole job is to notify clients should be able to change depending on how those clients need to be notified. And our service which really doesn’t care about the implementation details of those handlers can get on with it’s work.

In saying that, later on we will see how we use DI to really help us ease the load from both classes and yet still stick to heart of the Mediator Pattern.

MediatR Library

The MediatR library describes itself as “Simple, unambitious mediator implementation in .NET”. In particular, I like the word “Unambitious” being used. It’s somewhat refreshing in a world of Hacker News posts that claim to be releasing a library that will change the way we write code forever. You may also recognize the author of MediatR as Jimmy Bogard who also maintains AutoMapper!

MediatR is essentially a library that allows in process messaging – which in turn allows you to follow the Mediator Pattern! Easy! Let’s get started

Installing MediatR

The first thing we need to do is install the MediatR nuget package. So from your package manager console run :

Install-Package MediatR

We also need to install a package that allows us to use the inbuilt IOC container in .NET Core to our advantage (We’ll see more of that shortly). So also install the following package :

Author:

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.