Dealing with Duplication in MediatR Handlers

We’ve been using MediatR (or some manifestation of it) for a number of years now, and one issue that comes up frequently is “how do I deal with duplication”. In a traditional DDD n-tier architecture, you had:

  • Controller
  • Service
  • Repository
  • Domain

It was rather easy to share logic in a service class for business logic, or a repository for data logic (queries, etc.) When it comes to building apps using CQRS and MediatR, we remove these layer types (Service and Repository) in favor of request/response pairs that line up 1-to-1 with distinct external requests. It’s a variation of the Ports and Adapters pattern from Hexagonal Architecture.

Recently, going through an exercise with a client where we collapsed a large project structure and replaced the layers with commands, queries, and MediatR handlers brought this issue to the forefront. Our approaches for tackling this duplication will highly depend on what the handler is actually doing. As we saw in the previous post on CQRS/MediatR implementation patterns, our handlers can do whatever we like. Stored procedures, event sourcing, anything. Typically my handlers fall in the “procedural C# code” category. I have domain entities, but my handler is just dumb procedural logic.

Starting simple

Regardless of my refactoring approach, I ALWAYS start with the simplest handler that could possibly work. This is the “green” step in TDD’s “Red Green Refactor” step. Create a handler test, get the test to pass in the simplest means possible. This means the pattern I choose is a Transaction Script. Procedural code, the simplest thing possible.

Once I have my handler written and my test passes, then the real fun begins, the Refactor step!

WARNING: Do not skip the refactoring step

At this point, I start with just my handler and the code smells it exhibits. Code smells as a reminder are indication that the code COULD exhibit a problem and MIGHT need refactoring, but is worth a decision to refactor (or not). Typically, I won’t hit duplication code smells at this point, it’ll be just standard code smells like:

  • Large Class
  • Long Method

Those are pretty straightforward refactorings, you can use:

  • Extract Class
  • Extract Subclass
  • Extract Interface
  • Extract Method
  • Replace Method with Method Object
  • Compose Method

I generally start with these to make my handler make more sense, easier to understand and the like. Past that, I start looking at more behavioral smells:

  • Combinatorial Explosion
  • Conditional Complexity
  • Feature Envy
  • Inappropriate Intimacy
  • and finally, Duplicated Code

Because I’m freed of any sort of layer objects, I can choose whatever refactoring makes most sense.

Dealing with Duplication

If I’m in a DDD state of mind, my refactorings in my handlers tend to be as I would have done for years, as I laid out in my (still relevant) blog post on strengthening your domain. But that doesn’t really address duplication.

In my handlers, duplication tends to come in a couple of flavors:

  • Behavioral duplication
  • Data access duplication

Basically, the code duplicated either accesses a DbContext or other ORM thing, or it doesn’t. One approach I’ve seen for either duplication is to have common query/command handlers, so that my handler calls MediatR or some other handler.

I’m not a fan of this approach – it gets quite confusing. Instead, I want MediatR to serve as the outermost window into the actual domain-specific behavior in my application:

Excluding sub-handlers or delegating handlers, where should my logic go? Several options are now available to me:

  • Its own class (named appropriately)
  • Domain service (as was its original purpose in the DDD book)
  • Base handler class
  • Extension method
  • Method on my DbContext
  • Method on my aggregate root/entity

As to which one is most appropriate, it naturally depends on what the duplicated code is actually doing. Common query? Method on the DbContext or an extension method to IQueryable or DbSet. Domain behavior? Method on your domain model or perhaps a domain service. There’s a lot of options here, it really just depends on what’s duplicated and where those duplications lie. If the duplication is within a feature folder, a base handler class for that feature folder would be a good idea.

In the end, I don’t really prefer any approach to the another. There are tradeoffs with any approach, and I try as much as possible to let the nature of the duplication to guide me to the correct solution.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in DomainDrivenDesign, MediatR. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Great article! I always enjoy those thoughts on architecture. Kudos.

    • Alistair Rigney

      I love the separation of concerns this pattern gives but one of the main benefit s of DDD is to be able to plug and play any new data access or ui tech.
      But it seems with this pattern that code duplication will ocur e.g you would need to cut and paste extension methods for each new data access tech or to avoid that you could attempt to have repositories that would only retrieve data and then reuse the data extension mehods. But that is using repositories again

  • +1 not having handlers depend on other handlers. I learned that lesson when I started introducing services to decouple business logic from controllers/UI etc. What do you do when services need to share logic? Novice approach is to have the services depend on other services (or sibling methods in the same service). I think the most helpful abstraction one can introduce in any typical enterprise app is what DDD calls “Application Services” along with the rule of thumb that they should never depend on each other – i.e. the “outermost” layer. Of course, MediatR handlers are application services. Bravo on a good library/abstraction for this. It’s helpful to have a separate abstraction for such an important architectural concept/principle.

  • JuandeDios Calix

    This is just getting better and better. Thank you very much Jimmy. It would be extremely helpful if you add examples of this to the contoso, just for reference sake.
    Once again thank you very much, can’t waiting for your next post and MediatR 3.0 with pipes built in support. Thanks, from Honduras, Central America.

    • jbogard

      ha! come te va?

      • JuandeDios Calix

        Hola Jimmy, Super bien desde que encontre el primero de tus recursos (guarde el link https://christiantietze.de/posts/2015/02/crafting-wicked-domain-models/)

        Its extremely hard to get all of this when you a have a poor/weak background (auque termine la universidad hace casi 6 años y empece a trabajar en este rubro de inmediato)

        But thanks to people like you, I think I’m (and everybody else at my work place) finally understanding how to properly start programming.

        Most of our development is webforms (ALL logic in the aspx.cs and a lot of raw sql, right next to it – 1 webforms project, some times up to 100 diferent aspx files with 100s of lines of code)

        luckly our boos is pretty open minded and about 2 years ago I started researching and we are kind of doing DDD-NLayer (DAL, Domain (Entities/VMs/Dtos/StaticHelpers) Generic Repository and UoW Pattern, Application Layer and WebServices (WebApi) / WebForms as client layers, with some pretty raw HTML/JS/CSS dynamic reports. but everybody just feels awkard, a lot to remember (A lot of repositories and services, with dozens of methods, pretty much the same) we do started using IoCs (Unity/Ninject) – but… we did not even understand DesignPatterns or even SOLID OOP (we were 3 people, now we are 14).

        Right now Im trying to defined a new way of doing thinks, CQRS MediatR for server side, right up to the controller, the controllers will be extremely thin (just for Autho/Authe/Route) cause we now have 3 developer that works on client side only (Angular1) I was trying to use ASP.net MVC, with strongly type views/Partial/Components/YourMVCconventions. But, they cannot start learning to much right now, cause they already start learning Angular2, but using the AngularGuide by JohnPapa and not just Angular as Helpers (like they do right now).

        Either way, you posts, frameworks (AutoMapper, MediatR and the example projects) along Microsoft .Net tools, IdentiyServer, XamarinNativeTools will be thea guide to a better programming path. Thank you very, very much. This is exactly what we needed to find, cause with our salary or project budgets, we rarely are able to pay a month or two at Pluralsight. and to be honest, your post and tooling was the kind of content I needed to start using/applying what Ive learnd the past 2 years. please keep up helping developers from around the world with your (and team) knowledge . THANK YOU.

  • Another option I have used often is to have a handler implement two Mediatr interfaces. This can be handy to extract some logic into private methods, but also when they have largely the same dependencies.

    I prefer that over creating a base handler class, because it keeps the code in a single place, but I guess that´s more a matter of preference.