As your computer application gets more complex, more classes may be added. So, the more classes you add, the more difficult it can be to communicate between these classes. This can be a problem if these classes are located in different assemblies.
This is where the mediator design pattern comes in. With the mediator design pattern, the objects communicate within the mediator object, rather than directly with each other. As a result of this, it reduces dependencies on objects that communicate with each other, eliminating coupling.
There are many third party mediator design patterns out there. The one we will concentrate on is MediatR. MediatR is descibed as a "Simple mediator implementation in .NET" on their GitHub repository, and we are going to use it in this article.
We are going to use MediatR in a simple ASP.NET Core application, but first we need to know how it works.
How does MediatR work?
MediatR works in three stages:
- We create a request. The request is a custom class that you can set up
- The request is sent to a request handler, which does the work you want it to do
- As a result of the request handler finishing, it will return a response class, which is a custom class that you can set up
Here is a chart of how it exactly works.
Now for our example
So we are going to create a MediatR example a ASP.NET Core application. But first things first, you will need to add the following dependencies to your application, which are written by Jimmy Bogard:
We are now going to set up the request and response class. The point in this is that the request class is going to have two numbers. The response class will have the total.
Next, it's time to set up the request handler. It will take the two numbers in the request handler and add them together. It will then return the total of this addition into the "response" class.
You may have noticed in the request and request handler classes that we are inheriting some interfaces. These interfaces are from the MediatR library.
The IRequest interface is a generic method that expects the name of the class that is going to contain the response. This is always inherited in the request class.
The same story is with the IRequestHandler interface, only that it inherits the request handler class and expects the request and response classes as it's generic dependencies.
How to add MediatR to Dependency Injection
Earlier, we mentioned that we had to include the MediatR.Extensions.Autofac.DependencyInjection package. As you may have guessed from the package name, this allows us to use MediatR as part of Dependency Injection. If we include services.AddMediatR(typeof(Startup).Assembly) inside the ConfigurationServices method in Startup.cs, this makes it as part of dependency injection.
Run MediatR from a Controller
Now that we have MediatR as part of dependency injection, we can use it as part of our MVC application. This MediatR object is stored within the IMediator class and we can pass that in as a parameter into our controller constructor.
Then, it's a case of setting up an action, creating our request. With this request, we send it through mediator and get our response.
In the example above, we have outputted the result into the view.
Adding to Dependency Injection
We haven't told our web application that if we send a particular request class through mediator, we expect to return a particular response class. This is where we can add it in dependency injection.
It's a case of adding a new transient method in dependency injection and including the interface and class name of the request handler within it.
Simplifying the application
Obviously, my example is very simple to make it easier for you to understand. As explained earlier, the whole point of the mediator design pattern is to use this pattern to connect classes that may be in different projects.
If you connect these classes directly, you may have problems with circular dependency. This is where one assembly relies on another and vice-versa. This is not possible to do in a .NET application.
If you wish to download the above example, it is available in my GitHub respository, or you can view the full example below: