This is Part 3 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
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 :
Install-Package MediatR.Extensions.Microsoft.DependencyInjection
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.
public void ConfigureServices(IServiceCollection services) { services.AddMediatR(Assembly.GetExecutingAssembly()); //Other injected services. }
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).
public class NotificationMessage : INotification { public string NotifyText { get; set; } }
Next we need handlers for the messages. That’s easy too, we just inherit from INotificationHandler and go from there!
public class Notifier1 : INotificationHandler<NotificationMessage> { public Task Handle(NotificationMessage notification, CancellationToken cancellationToken) { Debug.WriteLine($"Debugging from Notifier 1. Message : {notification.NotifyText} "); return Task.CompletedTask; } } public class Notifier2 : INotificationHandler<NotificationMessage> { public Task Handle(NotificationMessage notification, CancellationToken cancellationToken) { Debug.WriteLine($"Debugging from Notifier 2. Message : {notification.NotifyText} "); return Task.CompletedTask; } }
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 :
public interface INotifierMediatorService { void Notify(string notifyText); } public class NotifierMediatorService : INotifierMediatorService { private readonly IMediator _mediator; public NotifierMediatorService(IMediator mediator) { _mediator = mediator; } public void Notify(string notifyText) { _mediator.Publish(new NotificationMessage { NotifyText = notifyText }); } }
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 :
services.AddTransient<INotifierMediatorService, NotifierMediatorService>();
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.
public class HomeController : ControllerBase { private readonly INotifierMediatorService _notifierMediatorService; public HomeController(INotifierMediatorService notifierMediatorService) { _notifierMediatorService = notifierMediatorService; } [HttpGet("")] public ActionResult<string> NotifyAll() { _notifierMediatorService.Notify("This is a test notification"); return "Completed"; } }
Running all of this and opening up our debug panel we can see :
Debugging from Notifier 1. Message : This is a test notification Debugging from Notifier 2. Message : This is a test notification
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.
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.
Thanks for your comment. All good stuff!
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.
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.
Great article! thanks
Thanks for your great post.
How to implement Conditional Handlers in MediatR ?
It much looks like CQRS pattern to me.
https://martinfowler.com/bliki/CQRS.html
Are they really different patterns? how can we tell them apart?
Don’t quote me on this, seems like Mediatr is an “implementation” of a .NET library of the CQRS pattern
https://www.bilaalsblog.com/mediatr-and-cqrs-pattern-software-architecture/
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).
Hi there,
Maybe best if you upload your existing code to a Github repo and from there can take a look?
Nice article, but for MediatR, next is missing i gues in ConfigureServices 😉 :
services.AddTransient<INotificationHandler, Notifier1>();
services.AddTransient<INotificationHandler, Notifier2>();
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.
It doesn’t work for me. I needed to add these services (using netcore 3.0)
services.AddTransient<INotificationHandler, HistoricManager>();
services.AddTransient<INotificationHandler, WeatherManager>();
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.
Oh right. That’s the problem. Got It.
Thanks, Wade and great article.
Hello,
Thank you for your explanation, i just have a small question, You mentioned in the Creating Our Mediator Service part that you prefer to add an abstraction on the top of the mediator using a service, but the problem is that abstraction is not very useful because you are using the IRequest interface directly in your Notifications.
Is there is a way to avoid this ?
That’s correct. It’s far from ideal having a direct dependency between the messages an MediatR, but afaik MediatR requires this marker interface in all the messages (events).
Personally that’s a reason I use another library Enexure.MicroBus with a wrapper because it has a mode where you don’t need to mark your messages and you can be completely agnostic of underneath technology.
I am thinking of rolling my own super-simple implementation just with Publisher-Consumers mode available without any marker interface requirement for the messages.
The send-receive command mode I don’t like using it and I don’t think a command or query sending needs MediatR or the mediatr pattern at all because when it should be a one-to-one communication where the sender knows the receiver, so as others have already mentioned there’s no point in abstracting this knowledge and it causes annoyance when debugging or reading code.
I see mediator pattern useful in one-to-many communication (with events/notifications) where the publisher really shouldn’t know anything about consumers.