Why use MediatR? 3 reasons why and 1 reason not

Why use MediatR? 3 reasons why and 1 reason not

The MediatR library by Jimmy Bogard has become increasingly popular over recent years, and deservedly so. By its own definition, it’s a simple, unambitious mediator implementation in .NET. Why are so many developers using it? Why should you use MediatR? Here are 3 reasons why you should at least consider using it and one reason why shouldn’t.

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts including this one regarding MediatR.

What is MediatR?

For those unfamiliar with MediatR library or the mediator pattern:

In software engineering, the mediator pattern defines an object that encapsulates how a set of objects interact. This pattern is considered to be a behavioral pattern due to the way it can alter the program’s running behavior.

Reason #1: Decoupling

Most examples I’ve seen using MediatR are with ASP.NET Core, but that doesn’t mean that’s the only framework where it’s useful. The point is decoupling your application code from the top-level framework code. Whatever code is actually in charge of executing your code.

Here’s a example using ASP.NET Core MVC

The point is creating a request object that you pass to MediatR which in turn invokes the correct Handler for that request object.

The PlaceOrderHandler has no references to any types or APIs in ASP.NET Core.

Reason #2: Application Requests

The reason why decoupling from top-level framework code such as ASP.NET Core can be important is to ask yourself: Is the application I’m creating an application or a web application?

There’s a difference between a web application and just an application.

An application can have many different inputs. Not all incoming requests are going to be via HTTP. There may be various ways that interact with your application.

For example, you could have recurring jobs that need to perform specific actions at a given time during the day. Or you may also have work that gets triggered from specific messages you’re picking up from a Message Broker.

There are a number of ways that you may want to invoke behaviors in your system that don’t initiate from an HTTP request.

In my example above with ASP.NET Core, we’re ultimately converting an HTTP request into an Application Request. That Application request is entirely decoupled from any specific top level framework and could be invoke from anywhere.

Using MediatR to create application requests to cross an integration boundary.

Reason #3: Request Pipelines

Once you start thinking about application requests, you can go deeper into creating a pipeline for those requests.

If you’re familiar with ASP.NET Core middleware, the purpose is to define a pipeline for an HTTP request.

You can create the same concept using MediatR behaviors. There are a few different ways to create them but here’s an example of a that implements the IPipelineBehavior

When you call mediator.Send() this behavior is called first prior to your primary handler (PlaceOrderHandler). The RequestHandlerDelegate which is a delegate to call PlaceOrderHandler. This allows us to do primary work before calling it or possibly even short-circuiting and not calling it at all, say if we had some validation issues.

This means you could have any number of pre-processors that can be run prior to the primary handler, or post-processors that can be run after.

Why use MediatR

This is incredibly powerful and allows you to separate different concerns related to a given application request.

Why Not?

The reason you may not want to use MediatR is simply that everything is done in-process. Meaning that wherever process is calling mediator.Send() is also the same process that is executing the relevant Handler for that request.

Udi Dahan the founder of NServiceBus posed this question on Twitter with my response.

Why use MediatR

With everything in-process, this becomes really apparent with Events/Notifications (MediatR calls them Notifications).

A notification can have zero or multiple handlers. However the execution of all the notification handlers are done all in the same process.

Why use MediatR

In the example above, if you publish a notification to MediatR, and there are 3 handlers for that notification, it will execute all 3. But what happens if one of them fails and throws an exception?

That exception will bubble up back to where you published the message via MediatR. How do you want to handle this? Can you re-publish that message again and have the handlers that succeeded run again? What if one of them was sending an email?

You want event/notification handlers to be run in independently in isolation. This is where out-of-process messaging comes in.

In this case, you might want to look at NServiceBus, Brighter, MassTransit, Rebus.

More

If you want more details on how MediatR works, I’ve talked and written about this in my Fat Controller CQRS Diet where I use MediatR as an example on how to decouple your application code from top-level framework code.

Follow @CodeOpinion on Twitter

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Solution & Project Structure of a Loosely Coupled Monolith

Solution & Project Structure of a Loosely Coupled Monolith

Here’s how you can create a solution and project structure to develop a loosely coupled monolith using a .NET Solution with C# Projects.

Each boundary is in a solutions folder with 3 projects. Implementation, Contracts, and Tests. All of which are class libraries. The two top-level executable projects, AspNetCore and Worker are console applications that reference the implementation projects.

Loosely Coupled Monolith

This blog post is apart of a series of posts I’ve created around Loosely Coupled Monoliths.

YouTube

Check out my YouTube channel where I post all kinds of content that accompanies my posts.

System Diagram

Here’s a diagram of what the Solution and C# project structure should reflect.

Solution & Project Structure of a Loosely Coupled Monolith

Bounded Context

The middle row of the diagram has 3 boxes that represent a boundary. These boundaries should define the set of capabilities of your system. Each boundary contains 3 projects: Contracts, Implementation, and Tests.

Solution & Project Structure of a Loosely Coupled Monolith

In my example above, there are 2 boundaries: Sales, and Shipping. For each one, I’ve created a solutions folder which the 3 respective projects for each boundary inside. All 6 projects are C# Class Libraries.

References

Each implementation project (Sales & Shipping) will only reference other Contract projects. They will never reference another implementation project.

Solution & Project Structure of a Loosely Coupled Monolith

The example above has the Sales implementation referencing the Shipping.Contracts.

Top-Level

There are two top-level projects that are our executable projects. AspNetCore and a Message Process (Worker).

Top-level projects will reference the implementation projects to expose their capabilities

ASP.NET Core

This top-level project is an ASP.NET Core app. Which is really just basically a console app using Kestrel as the HTTP server.

Dependencies

The mentioned this project will reference the Sales and Shipping projects.

This is because each implementation project must define its own configuration. Things like Dependency Injection, HTTP routing, etc.

ConfigureServices

The above example is of an extension method for defining all of the types that needed to be registered with a ServiceCollection. In the case above it’s adding the Entity Framework SalesDbContext.

This can then be used in the AspNetCore’s ConfigureServices.

ASP.NET Core

Worker

The Message Processor (Worker) is the other top-level project that is a console application. Its purpose is to connect to a message broker and dispatch the relevant messages to the implementation projects. I’ll cover message processing in other blogs/videos as the purpose of this post is simply the solution and project structure.

As you can expect, it will reference the implementation projects and use the extension methods just as the AspNetCore project does.

Generic Host

The Worker is using the Generic Host which is very similar to the WebHost from ASP.NET Core. It provides all the same goodness that you get with an ASP.NET Core app such as Dependency Injection and Logging.

In this case, I’m creating a HostedService which is a BackgroundService. This is ultimately where we would be communicating with a message broker to dispatch and handle messages within our Monolith.

Again, more on how that works in other posts (which will be linked at the bottom of this post when they are published).

Questions or Feedback

If you have any questions or comments, let me know in the comments of the YouTube video, in the comments on this post or on Twitter.

Follow @CodeOpinion on Twitter

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.

Migrating to .NET Core: Mission Complete

Migrating to .NET Core: Mission Complete

It’s been over 5 years since I started a greenfield project that initially was developed using Katana/Owin with ASP.NET Web API. Over the past 3 years, since .NET Core 2.0 was released and .NET Standard 2.0 was defined, I’ve been slowly chipping away at migrating to .NET Core. It’s been a long road but we’re now fully migrated and running in production with ASP.NET Core on .NET Core 3.1.

Migrating from .NET Framework to .NET Core

This blog post is in a series about migrating from .NET Framework to .NET Core.

Solution/Project Size

To give some sense of scale, our application consist of two primary entry points.

The first is an HTTP API that started out as a shelf hosted (not using IIS) Owin/Kata using ASP.NET WebAPI. Over time that morphed into using Nancy. During the migration, it ultimately moved to ASP.NET Core using the OWIN Middleware to still use Nancy.

The second entry point is a worker process that processes messages from a message broker. This is primarily for handling events and fire-and-forget commands. This has always been a console app.

To give a sense of scale, I ran NDepend over our solution to get lines of code metric, just to give some idea of the size.

Migrating to .NET Core

Journey: Migrating to .NET Core

I’ve given a full experience report on my YouTube channel. This covers pretty much everything I’ve done along with the process of getting our app running under .NET Core in production.

Questions or Feedback

If you’re thinking of doing a migration and have any questions, let me know in the YouTube comments, in the comments on this blog or on Twitter. I’d be glad to help if possible.

If you’ve done a migration and would like to share some tips, get in touch with me!

Follow @CodeOpinion on Twitter

Enjoy this post? Subscribe!

Subscribe to our weekly Newsletter and stay tuned.