Sponsor: Do you build complex software systems? See how NServiceBus makes it easier to design, build, and manage software systems that use message queues to achieve loose coupling. Get started for free.
This post is in my Fat Controller CQRS Diet series demonstrating how to thin your controllers by implementing commands and queries using the MediatR library. For demonstration, I’m converting the MusicStore application that’s using ASP.NET Core MVC. All the source code is available on GitHub. If you’re new to this series, here are earlier posts in this series:Pipelines
In both the new Query and Commands handlers wrote in prior posts, there was one thing standing out that really didn’t belong. Logging For reference, here was ourAddToCartHandler
that did some logging at the end of the method.
This really isn’t a concern of our AddToCartHandler
. One way we can separate logging out is by having our Command go through another handler after it’s been executed. If we think about this a bit more broad, we can take it a step further and create a pipeline for our Command that can go through various handlers prior and after the main AddToCartHandler
.
Video
If you prefer, I have a video tutorial that follows this blog post.Decorators
One way to accomplish this is to use Decorators. A decorator is nothing more than wrapper around our main handler. In our example, we are going to use StructureMap. In your project.json, add the following dependencies. Next in our Startup.cs we are going to configure StructureMap in theIServiceProvider ConfigureServices(IServiceCollection)
method.
The gist is we are going to Decorate/Wrap any ICancellableAsyncRequestHandler<TRequest,TResponse>
in a Pipeline<TRequest,TResponse>
(which we will create next).
Here is our implementation of the Pipeline<TRequest,TResponse>
It will take the primary request as the first argument in the ctor, and then a array of IPostRequestHandler<TRequest,TResponse>
, which we will create next to define our logging handlers.
Log Handler
We now have everything in place to separate the logging from ourAddToCartHandler
.
All we need to know is create a class that will implement IPostRequestHandler<AddToCart,Unit>
and it will be invoked after the AddToCartHandler
.
Now we can jump back over to our AddToCartHandler
and remove the ILogger
and the logging code.
The pipeline pattern is so powerful when it comes to handlers. One could push it even further, to handling queries making a single handler responsible only for one business thing and delegating the rest to other handlers. It might be perceived as over engineering, on the other hand it saved me a lot of grey hair when dealing with a legacy application (it was easy to close every unit in a handler).
Mentioning the decorators: 2nd lvl cache with an sql cache dependency, a glimpse decorator (showing all fanned out requests from the original one) and many more. If all your components are handlers, decorators will save your day.
Thanks for the comment. Much appreciated insights. Interesting idea about having a single handler and delegating out. I need to think about this a bit more. In regards to decorators, there’s been some discussion on the MediatR github repo about how to best handle decorators and if DI containers are the best way.
https://github.com/jbogard/MediatR/issues/102
Using MediatR’s notification maybe is a way to implement it https://jonhilton.net/2016/08/31/how-to-easily-extend-your-app-using-mediatr-notifications/
Pingback: MediatR Behaviors - CodeOpinion