MediatR — Beyond the basics
RequestHandler, NotificiationHandler, and StreamRequestHandler.
Have you heard about MediatR?
If you are a .Net developer, of course, you have.
MediatR is a fantastic library that implements the pattern Mediator.
If you don’t know yet what is mediator patterns, please check this link before. https://sourcemaking.com/design_patterns/mediator
The main goal is to design reusable components with “loose coupling.”
After this brief introduction, let's go to what really interests us, CODE. :)
For us “luminous beings(.net devs),” we have this awesome library called MediatR.
https://github.com/jbogard/MediatR
Here in this post, we will talk about the three main capabilities that this one has.
The most used RequestHandler.
This one consists in creating a decoupling class for requests that implement IRequest<T> from MediatR.
Another class for the response this one does not need to implement any interface.
And the last for handle it, where we will need to implement IRequestHandler<TRequest, TResponse>.
Until here nothing “beyond the basics”…
Do you know that you can add a class to pre-process for each request you want?
For this, you need to create a class that implements IRequestPreProcessor<TRequest> like this:
And booooom, yes, you add a new step to the pipeline request.
Just like pre-processing, we can need to do something on post-processing. For this, we need to implement the right interface. IRequestPostProcessor<TRequest, TResponse>
Do you wanna more? What do you think about handler any exceptions when handling a request?
Yes, we can do this.
And for this, we have two possibilities.
This one, IRequestExceptionAction<,>
IRequestExceptionAction: The Implementation will receive the exception inside MediatR’s pipeline before throwing it.
One exception without treatment will still crash the application after this action.
The other is more powerful.
lIRequestExceptionHandler: The implementation could handle the exception.
When you handle the exception the application will not crash after this.
We can want to have a handler like this for many reasons. For me, one of the most important is that we can make applications more resilient, thinking of solutions for fallback.
How to send a ‘Request’ inside our application with MediatR?
We need to inject IMediator interface.
And send the request that you want to.
As simple as it seems.
That is it about RequestHandler. Please let me know if I have missed something.
INotificationHandler.
Yes, we can do this.
The implementation is very similar to RequestHandler. The big difference is that you can have as many handlers as you want.
And how can it be helpful?
So, for example, we can notify different parts of our application that something has happened. With this, we can change our state without needed pull data from somewhere.
An observation, for default, the NotificationPublisher uses ForeachAwaitPublisher implementation, and this makes that notification works like a queue, and if you have one problem in one, the next will not be called.
Thanks to dependency injection, we can change the default implementation to TaskWhenAllPublisher.
As you can imagine, yes, we can also create our implementation.
Another difference is that Notifications can not return a result and should be marked as INotification.
How to send a notification inside our application with MediatR?
After injecting IMediator, we should ‘Publish’ instead ‘Send’ our notifications.
IStreamRequestHandler.
Yes, definitely, we can do this. It’s amazing.
Now you should imagine that StreamRequest should use another interface, and yes, you are right!
We need to use IStreamRequest<TResponse> for this.
And the handler should implement IStreamRequestHandler<>
Yeah, you should notice that this interface returns IAsyncEnumerable.
Working with AsyncEnumerable should be hard, or at least different, at the first moment. So, let’s explain this.
How to use this inside our application with MediatR?
First, with IMediator injected, we need to create a stream calling the method CreateStream<Response>(Request).
This method will return an AsyncEnumerable that we cannot assume when it will stop sending data. For our handler, we force a break when the count is 10.
This is powerful.
Remember that we can use this library in any .net application. In my repository, I use a console application, but you can add this library to Xamarin, Maui, WPF, Asp net, etc.
So, I hope this post can be useful for someone else.
And below, you can find the references I used to create my proof.
Remember, Do your best even when you’re not so happy, and you will see things changing.
Thank you all.
My Repo
https://github.com/CristianLopes/ConsoleMediatR
MediatR GitHub
Nick Chapsas