The Mediator Pattern In C# .NET – Part 2 – Roll Your Own

This is Part 2 of a series on using the Mediator Pattern in C# .NET. You’ve probably missed out on some important stuff if you’re starting here so make sure to head back and read Part 1 before reading on!


The Mediator Pattern In C# .NET

Part 1 – What’s A Mediator?
Part 2 – Roll Your Own
Part 3 – MediatR


The “IEnumerable” Pattern

The “IEnumerable” Pattern is something I’ve used for the past 5 or so years in almost every single project I’ve worked on. It came about as a “that’s a cool feature” type thing when I found out that several IOC Containers would automatically inject an IEnumerable<T> into a class if you bind multiple types to the same interface (That may sound confusing but it will make sense once we get into the code).

This little hunk of code that I use isn’t specifically a “Mediator” pattern. But when I think about a core defining characteristic of the Mediator pattern :

“It promotes loose coupling by keeping objects from referring to each other explicitly”

Then this gets very close to doing so.

Let’s look at an example. For this I am going to use a standard .NET Core Web API project. Nothing fancy. In it, I have an interface with two implementations of that interface.

public interface INotifier
{
    void Notify();
}

public class Notifier1 : INotifier
{
    public void Notify()
    {
        Debug.WriteLine("Debugging from Notifier 1");
    }
}

public class Notifier2 : INotifier
{
    public void Notify()
    {
        Debug.WriteLine("Debugging from Notifier 2");
    }
}

In my startup.cs, I then bind these two classes to the INotifier interface.

public void ConfigureServices(IServiceCollection services)
{
    services.AddTransient<INotifier, Notifier1>();
    services.AddTransient<INotifier, Notifier2>();
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

Then I have a super simple controller just to demonstrate what we’ve done.

public class HomeController : ControllerBase
{
    private readonly IEnumerable<INotifier> _notifiers;

    public HomeController(IEnumerable<INotifier> notifiers)
    {
        _notifiers = notifiers;
    }

    [HttpGet("")]
    public ActionResult<string> NotifyAll()
    {
        _notifiers.ToList().ForEach(x => x.Notify());
        return "Completed";
    }
}

I hit this endpoint and in my debug window, what do I see?

Debugging from Notifier 1
Debugging from Notifier 2

Super simple right? Now as I add, remove, modify the notifiers, or they add extra logic on when they need to be run. The list itself is simply injected into the controller each time (And could be injected anywhere else). In this way, the caller doesn’t actually need to change when additional classes are added or removed, and it doesn’t need to expand out it’s action, it stays exactly the same.

Making It A Bit More “Mediator”-ish

Someone looking at this might feel that it still leaks a little bit of implementation detail. But that’s easily wrapped up if we really wanted to go all out on a mediator service class. For example, let’s create a service like this :

public interface INotifierMediatorService
{
    void Notify();
}

public class NotifierMediatorService : INotifierMediatorService
{
    private readonly IEnumerable<INotifier> _notifiers;

    public NotifierMediatorService(IEnumerable<INotifier> notifiers)
    {
        _notifiers = notifiers;
    }

    public void Notify()
    {
        _notifiers.ToList().ForEach(x => x.Notify());
    }
}

In our ConfigureServices method of our startup.cs, we need to register this new service with the following line :

services.AddTransient<INotifierMediatorService, NotifierMediatorService>();

And finally, we need to go and wire this all up for use. Let’s change our controller to look a bit more like this :

public class HomeController : ControllerBase
{
    private readonly INotifierMediatorService _notifierMediatorService;

    public HomeController(INotifierMediatorService notifierMediatorService)
    {
        _notifierMediatorService = notifierMediatorService;
    }

    [HttpGet("")]
    public ActionResult<string> NotifyAll()
    {
        _notifierMediatorService.Notify();
        return "Completed";
    }
}

That’s pretty snazzy and fits more with the Mediator pattern, but still affords us the niceness of our Mediator not having to constantly change when we add or remove handlers!

Conditional Handlers

While not strictly related to the Mediator Pattern, you’ll also often find that Mediator Pattern libraries afford ways to conditionally run a handler. This could be based on particular conditions or just a type. An extremely common pattern that I end up with is some sort of “CanRun” method being put onto the interface. It could take inputs or it could just check some data in the background. It might look like so :

public interface INotifier
{
    void Notify();
    bool CanRun();
}

public class Notifier1 : INotifier
{
    public void Notify()
    {
        Debug.WriteLine("Debugging from Notifier 1");
    }

    public bool CanRun()
    {
        //Check something. And return True if it can run. 
        return true;
    }
}

Then when we need to run it from a list, we can just use Linq to filter it :

_notifiers.Where(x => x.CanRun()).ToList().ForEach(x => x.Notify());

I’ve done this in a tonne of different ways with huge success.

What’s Next?

In the next article in this series we are going to take a look at the “MediatR” library. A very popular in .NET that utilizes the Mediator Pattern. You can check out that article here!

3 thoughts on “The Mediator Pattern In C# .NET – Part 2 – Roll Your Own”

    • Hey Metz,

      I personally prefer the Foreach style in Linq which is only available on Lists. But if you would like to do the full ForEach loop the old way that’s cool too 🙂

      Reply

Leave a Comment