[.NET Core] Using CQRS pattern with MediatR [Part 1]
By: Duc Ho
Tags: Software Architecture, Cqrs, Mediatr, Design Patterns, Aspnetcore

This post series will introduce to you the CQRS design pattern, and how to implement this pattern in a real world example with MediatR at .NET Core

Next Part

[.NET Core] Using CQRS pattern with MediatR [Part 2]

Context and problem

In traditional architectures, the same data model is used to query and update a database. That’s simple and works well for basic CRUD operations. In more complex applications, however, this approach can become unwieldy. For example, on the read side, the application may perform many different queries, returning data transfer objects (DTOs) with different shapes. Object mapping can become complicated. On the write side, the model may implement complex validation and business logic. As a result, you can end up with an overly complex model that does too much.

Read and write workloads are often asymmetrical, with very different performance and scale requirements.

The traditional architecture

There is often a mismatch between the read and write representations of the data, such as additional columns or properties that must be updated correctly even though they aren’t required as part of an operation.

Data contention can occur when operations are performed in parallel on the same set of data.

The traditional approach can have a negative effect on performance due to the load on the data store and data access layer, and the complexity of queries required to retrieve information.

Managing security and permissions can become complex because each entity is subject to both read and write operations, which might expose data in the wrong context.

Solution

CQRS addresses separate reads and writes into separate models, using commands to update data, and queries to read data.

Commands should be task-based, rather than data-centric. (“Book hotel room,” not “set ReservationStatus to Reserved.”) Commands may be placed on a queue for asynchronous processing, rather than being processed synchronously.

Queries never modify the database. A query returns a DTO that does not encapsulate any domain knowledge.

The models can then be isolated, as shown in the following diagram, although that’s not an absolute requirement.

The CQRS basic architecture

MediatR is an open source implementation of the mediator pattern that doesn’t try to do too much and performs no magic. It allows you to compose messages, create and listen for events using synchronous or asynchronous patterns. It helps to reduce coupling and isolate the concerns of requesting the work to be done and creating the handler that dispatches the work.

Thin Controllers

In the traditional Controllers, you usually implement almost business logic flow in like as Validation, Mapping Objects, Savings Object, or Get Object, Return HTTP status code of request and the data response if have. However, if you will loop almost these steps again in every controller, your controller will get more fat. And who will maintain these controllers like this, I believe you will want to throw it away because too hard to see, let’s see these pseudo codes:

We can replace by these simple pseudo code like this:

CQS

This approach allows separate read and write operations. But for commands and queries, we need some handlers. And this is exactly where we can apply MediatR library.

As I mentioned before, this library is a simple implementation of MediatR pattern. This pattern allows implementing commands/queries and handlers loosely coupled.

Example MediatR

For example, I would like to implement code to get a user’s detail

Request

When you start using MediatR library, the first thing you need to define is request. Requests describe your commands and queries behavior.

The GetUserDetailQuery class describes a query that requires Id and returns the User data transfer object. All requests should implement IRequest interface. This interface is a contract which will be used by the handler to process request.

Handler:

When a request is created, you will need a handler to solve your request:

All handlers should implement IRequestHandler interface. This interface depends on two parameters. First — request, second — response. More details about requests and handlers you can find here.

Controller

So, we have our query and handler, but how to use them?

All you need is to define controller, inject mediator and send the query. That’s all.

In the first part, I have introduced the basic of CQRS architecture and how to implement it with MediatR.

In the next part, I will show you how to implement a real-world example.

The source code for the next part already done and published in Github: