The Mediator Pattern In .NET Core – Part 3 – MediatR Library

This is Part 3 of a series on using the Mediator Pattern in .NET Core. 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 .NET Core

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


Learning Design Patterns?

Did you know that many design patterns you work with today were first described in the book “Design Patterns: Elements of Reusable Object-Oriented Software” all the way back in 1994. It’s basically the bible of software design. While this article is a great start (if I do say myself!), I cannot recommend this book enough to every new developer.
Grab Design Patterns : Elements Of Reusable Object-Orientated Software Here!

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 :

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 :

Finally we open up our startup.cs file. In our ConfigureServices method, we need to add in a call to register all of MediatR’s dependencies.

Creating Our Handlers

The first thing to note is that MediatR can be either do “send and receive” type messages, or it can do a “broadcast” type message. Taking our example from our previous article in the series, we are doing a more broadcast style of message (And a pretty simple one at that). Let’s just stick with that for now.

In our original example, we weren’t passing through any information to our handlers, but in reality we are likely passing through some data. Basically a message if we think about traditional messaging systems. Let’s go ahead and just create a blank object that inherits from INotification  (An inbuilt type of MediatR).

Next we need handlers for the messages. That’s easy too, we just inherit from INotificationHandler  and go from there!

Super simple! We also don’t need to register these handlers anywhere, the initial line we added to our ConfigureServices method means that MediatR finds all handlers within the assembly and registers them correctly.

Creating Our Mediator Service

Now here’s the thing. We *can* just inject in the inbuilt IMediator interface everywhere and publish messages directly. Personally I’m not a huge fan because it’s basically telling everywhere “by the way, we use MediatR”. I prefer to abstract things away a little bit.

If we take our Mediator Service from the previous article, let’s just modify it a bit. Instead let’s build it like so :

So we have a NotifierService that still uses the IMediator class under the hood, but it means if we ever swap out libraries or change how we do notifications, only this class changes.

Because we have created a new service, we do need to remember to add the following line to our ConfigureServices method in our startup.cs file :

Using Our Notifier Mediator Service

Let’s use a super simple controller to run things. Again this is basically taken from Part 2 in this series and just modified a tiny bit to work with passing through notify text.

Running all of this and opening up our debug panel we can see :

Woo! Literally a 5 minute job to set up a completely in memory messaging system!

Final Thoughts On The Mediator Pattern

As we made our way through these 3 posts, it’s probably morphed a bit from the “Mediator Pattern” to “In Process Messaging”. But going back to our key bullet points from Part 1 :

  • 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.

We can see that In Process Messaging is actually just an “implementation” of the mediator pattern. As long as we are promoting loose coupling through a “mediator” class that can pass data back and forth so that the caller doesn’t need to know how things are being handled (By whom and by how many handlers), then we can say we are implementing the Mediator Pattern.

ENJOY THIS POST?
Join over 3.000 subscribers who are receiving our weekly post digest, a roundup of this weeks blog posts.
We hate spam. Your email address will not be sold or shared with anyone else.

14 comments

  1. First, I really like the idea of a custom, local class to hide the fact you’re using MediatR. However, your sample implementation is oversimplification and is far from real. What if I have 5 commands and 5 queries? And half of them have same ctor signature (accept string or Guid).
    Another issue is with the Mediator pattern in general, MediatR in particular, and your custom service the most – the ease to navigate from the caller of a handler to the handler implementation.
    As a workaround, some people continue to inject all handlers one by one. This way you keep the power of CQRS but do not take a hit to the code’s readability/maintainability/supportability. Don’t forget that the code you wrote today in few months you won’t recognize yourself, not to mention someone else.
    Another reason to inject all handlers explicitly is having too many of them would be a code smell and a sign of growing over-complexity of the class.

  2. There is one thing that stinks in MediatR, Request->Response pattern, a response stincks here so much that I need to write this down. Imagine that we have two handlers that are listenning to Message, and we are using two way communication here, which result we will have? Result from Handler1 or result from Handler2? Or maybe both? And here is a really nasty thing, it depends on version of MediatR, because in old version, you will get result from Handler1, and in new version you will have result from Handler2, depends on order of registrations.

    The other thing that is worring me that our customer wanted to use it in project to communicate between Controllers and Services in MVC project, which is madness because i wont be able to simply debug whole flow by clicking f11 to enter handler method. It worth mention to use MediatR only between packages, modules not between all classes in project, because if You want to make loosly coupled code you can use interfaces and dependency injection which is simpler to debug.

    1. Thanks for your comment, I didn’t know about the response pattern being that iffy. I personally haven’t used it that much because, maybe as you say, I usually require the response in a particular way and with the amount of code I would have to write on top of MediatR, I may aswell roll my own.

  3. Thank you for this article. Is the code available? I’m new to .NET and can’t really get the example to work. I have DotNet Core and VS Code installed and am probably 90% there, but the remaining bits are quite difficult (though probably basic for most).

  4. Nice article, but for MediatR, next is missing i gues in ConfigureServices 😉 :
    services.AddTransient<INotificationHandler, Notifier1>();
    services.AddTransient<INotificationHandler, Notifier2>();

    1. Hi Emmanuel,

      You actually shouldn’t need that. The call to

      finds all implementations of INotificationHandler and binds them inside the MediatR service. So we don’t need to add them to the service collection ourselves.

      1. It doesn’t work for me. I needed to add these services (using netcore 3.0)
        services.AddTransient<INotificationHandler, HistoricManager>();
        services.AddTransient<INotificationHandler, WeatherManager>();

      2. Leandro,

        Where is HistoricManager located? With the AddMediatR call above, you need to tell it which assembly the handlers are located in. The above will work if the handlers are in the same executing assembly (e.g. The web app), but if they are located elsewhere you would need to specify.

Leave a Reply

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