MediatR and me

I was only recently introduced to MediatR through the magic of Reddit.

Jimmy Bogard also does the excellent AutoMapper tool so it was work looking into. He’s written about his use of it for a long while on his blog

Flattening the layers

His posts on implementation patterns and dealing with duplication are the real gems though.

My particular problem is that in my three layers in my REST API, I find I’m constantly injecting new classes to try to avoid duplication of logic.  This MSDN post actually articulates the problem I’ve got with repositories and whatnot.

Given my layers:

  • Web (Controllers in ASP.NET Core terms)
  • Business stuff
  • Data Access

I want to keep some separation to concentrate on just testable logic my business layer. Web should just transform a request and call the relevent business object. The business logic needs data sometimes.

He says “I want MediatR to serve as the outermost window into the actual domain-specific behavior in my application” which is great. The end result is a Controller class that barely does anything except call IMediator.

However, I don’t want a handler that just duplicates my problem but just hides it behind MediatR so only my controller is prettier.  How do I organize things to be simplier while still having some layering with reusability and little duplication?

Handlers calling Handlers

Really what happens is that my “business” layer handlers end up calling other business handlers or data handlers.

My unit tests look like a series of these Moq statements:

mediator.Setup(x => x.Send(It.IsAny(), CancellationToken.None))
.Callback<IRequest, CancellationToken>((r,y) =>
var x = (Locations.NewLocation) r;
Assert.Equal(newSite.Name, x.Name);
Assert.Equal(userName, x.CreatedBy);
Assert.Equal(2, x.SiteId);
Assert.Equal(4, x.LocationTypeId);
Assert.Equal(345, x.ReportingUnitId);

I’m validating that I’m passing a message with MediatR and validating the message’s contents.

Is this bad?

It seems like it is.

MediatR basically just divides everything with loosely coupled message passing. It could all end up as a huge message soup with tons of layers of indirection.

Jimmy has a good example of how he uses MediatR, AutoMapper and other things with ASP.NET Core on github:

However, the logic is just a basic CRUD app. Nothing needs to share anything.

Is there anything that can stop that?

Just discipline I guess.

The good: a cache in the pipeline!

(I’m waving my hands with the implementation details of caching as that’s code for another post.)

I put a Redis cache on my reference data from the database.  I had a pattern around my data access but it was a lot of copy/paste.  Now, I have a marker interface for my requests and it just automatically caches because the MediatR pipeline just resolves it.

The cache pipeline handler with a marker interface is declared like this:

public class DistributedCachingHandler<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : class, IUseDistributedCache
where TResponse : class

Now, any request that goes through MediatR that implements the IUseDistributedCache will go through this pipeline handler.

Actually, the generics and type resolution is not done by MediatR but by your IoC container of choice.  I was sticking to the default container in ASP.NET Core.  However, the resolution isn’t as sophisticated as StructureMap, AutoFac, etc. and ends up erroring when trying to create pipelined types generically constrained by the marker the interface.  So now, I just plugged in AutoFac and still use IServiceCollection as I normally would.

The good part 2: FluentValidation and MediatR

(I’m waving my hands with the implementation details of this as that’s code for another post.)

FluentValidation is a good library for creating validation classes for various POCOs then the validation can just be plugged into anywhere.  I want this to be plugged into two places: when ASP.NET Core is accepting a model from a REST call (using an ActionFilter) and also in my MediatR pipeline!

I made a MediatR pipeline handler that takes any request/response pair and sends it through FluentValidation. If any Validators are registered, then they are ran.

For the Action Filter, FluentValidation is chained onto your AddMvc method and marks the ModelState as invalid. You can handle this in many ways but I made another Action Filter to automatically return when the Model is invalid.

3 thoughts on “MediatR and me

  1. Hi, in case you still tracking this.

    A regular pipeline behavior runs on every request, then I have to filter out by passive attribute on the request. I thought your solution would wire pipeline up selectively?

    I tried the following, but it only works if request implement IUseDistributedCache. If I call a request that does not have the interface, it throws an error complaining about TRequest violate covariant or something.

    Thought? Thanks.

    public class DistributedCachingHandler<TRequest, TResponse> :
    IPipelineBehavior<TRequest, TResponse> where TRequest : class,
    IUseDistributedCache where TResponse : class


Leave a Reply to Whoever Cancel reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s