In this article let’s us learn the basics of CQRS pattern using MediatR nuget package in .Net 5.
We know how a traditional web API works. It mainly consists of the CRUD operations. All the four operations are tied together inside an API controller.
- C – Create
- R - Read
- U – Update
- D – Delete.
To decouple the application we create interfaces for our data access layer, inject it in the constructor of API controller and perform the actions. This works fine and all looks good. But as your application grow in size the number of dependencies also increases. Now we need to inject multiple interfaces in the API controller and hence the application complexity increases.
In order to solve this problem, let’s use CQRS & Mediator Patterns.
CQRS stands for Command Query Responsibility Segregation. That is separating Command (write) and Query (read) models of an application to scale read and write operations of an application independently. Instead of having all of the four CRUD operations together, let us segment out to two different pieces.
Mediator is used to reduce communication complexity between multiple objects or classes. This pattern provides a mediator class which normally handles all the communications between different classes and supports easy maintenance of the code by loose coupling. Mediator pattern falls under behavioural pattern category.
Basically, a Mediator perform 2 operations.
- · Accept the incoming request
- · Handles the incoming request and provide the response.
CQRS + Mediator Patterns are prefered over large projects.
Let’s get into the code and see how this CQRS & Mediator patterns work together.
Read data using CQRS & MediatR
Step 1
Open Visual studio 2019. Create an ASP.Net Core Web API project named EmployeeManagement.API. I have given the solution name as EmployeeManagementDemo. (You can give any name of your choice).
Step 2
Make sure that you select the .Net 5.0 as target framework and enable the Open API support for Swagger and click create.
Step 3
Add a new class library project named EmployeeManagementLibrary. Select the target framework as .Net 5.0
Step 4
Delete the class1.cs file.
Step 5
Add folders named Data & Models. In the Models folder, add a class named EmployeeModel with three properties named Id, FirstName & LastName.
Step 6
Create a class named DataAccess and an interface named IDataAccess in the Data folder. In this example I am using an in-memory collection for storing data. If you want to try it out with any DB, you may add the logic to perform DB operations.
Step 7
Add two methods named GetEmployees & AddEmployees to the IDataAccess interface as shown in figure below.
Step 8
Let DataAccess class inherit from IDataAccess interface and implement the interface as shown in figure below.
Step 9
Now let’s add the MediatR nuget package to EmployeeManagementLibrary project. Browse for MediatR nuget package in install it.
At the time of writing this article the latest stable version of MediatR is 9.0.0.
Step 10
Add two new folders named Queries & Handlers in EmployeeManagementLibrary project.
Step 11
Add a class named GetEmployeeListQuery in the Queries folder. I am using records (C# 9 feature) instead of a class. If you are not familiar with records, I highly recommend you to go through it. Let us implement the IRequest interface of MediatR package as shown in figure below.
IRequest is a generic interface. We need to specify the return type of the request. In our case I have specified List<EmployeeModel> as I need to return all employees.
Step 12
We need to handle this request. For that let us add a handler class in Handlers folder. In our case I have added a class named GetEmployeeListHandler.
Step 13
GetEmployeeListHandler implements the IRequestHandler interface of MediatR package as shown in figure below.
IRequestHandler is a generic interface. So what do you mean by IRequestHandler<GetEmployeeListQuery,List<EmployeeModel>? It means that if the request is of type GetEmployeeListQuery, then return List<EmployeeModel>.
Step 14
Inject the IDataAccess in the GetEmployeeListHandler class and apply the logic to return all employees in the Handle method.
Step 15
Now let us go to the API project and configure the Startup services. Add the reference of EmployeeManagementLibrary.
Step 16
We need to configure the IDataAccess and the MediatR in the API project. Install the nuget package named MediatR.Extensions.Microsoft.DependencyInjection.
Step 17
Once the installation is complete, open the Startup.cs class file and configure the IDataAccess and MediatR in the dependency container.
I have added the MediatR to the services collection which can access all classes in EmployeeManagementLibrary project.
Step 18
Now let us create an API controller named EmployeesController. Inject the IMediator interface in the constructor and add logic to fetch all employees as shown in figure below.
Invoke the Send method of IMediator interface. The send method accepts a type of IRequest. In our case GetEmployeeListQuery is a type of IRequest.
Step 19
So, what happens behind the scenes is that when we invoke the Send method with the request as GetEmployeeListQuery, the mediator will invoke the handler which accept this request. In our case it will go and call the GetEmployeeListHandler class and returns the response as List<EmployeeModel>.
Step 20
Now run the API project. Since we have added the open API support, the swagger page will be displayed for testing our end points. Click on the api/Employees get method.
Step 21
Now let us see how to retrieve an employee by Id.
Step 22
As we did before, add a new query named GetEmployeeByIdQuery under the Queries folder in EmployeeManagementLibrary project. This time the query accepts a parameter named Id of type int and the response is of type EmployeeModel.
Step 23
Now let’s add a handler for this request as shown in figure below.
In this handler, instead of injecting the IDataAccess, I have injected the IMediator interface in the constructor. In the handle method, using the injected interface, I am trying to get all the employees by passing the GetEmployeeListQuery object and then filtering the employee with the Id passed as input. Here you can see that I am able to access the id passed as input using the request parameter.
In a real scenario we will be injecting the IDataAccess to retrieve the employee by Id from a database.
Step 24
Go to the API project -> Open EmployeesController and add a http get method which accept an integer parameter as shown below.
Note that I am passing the GetEmployeeByIdQuery(id)as the request. Run the API project and click on the Get button of api/Employees/{id}. Pass an input id=1 and verify the output.
I hope you all understood how to use the Mediator & CQRS pattern in reading data
Write Data using CQRS & MediatR
Step 1
Till now all Read requests are kept inside a Queries folder. All reads are treated as queries.
Step 2
All other CRUD operations except Read are kept under a Commands folder. Create a Commands folder in EmployeeManagementLibrary project.
Step 3
Create, Update & Delete operations are treated as Commands.
Step 4
Add a new record named AddEmployeeCommand which takes two parameters named FirstName and LastName. Make sure that this record inherits the IRequest interface of MediatR package as shown below. So, whenever the user request for AddEmployeeCommand, it returns an EmployeeModel.
Step 5
Create a handler for AddEmployeeCommand request. Add a class named AddEmployeeHandler in the Handlers folder.
The IDataAccess interface is injected in the constructor. Implement the Handle method of IRequestHandler<AddEmployeeCommand,EmployeeModel>. The FirstName and LastName inputs can be accessed from the request parameter.
Step 6
Open the EmployeesController of API project and include a Post method to add a new employee as shown below.
Step 7
Now run the API project and execute the post method in swagger UI by passing the following inputs and verify the ouput.
The response is a new employee with id=3.
So, we have learned how to use CQRS pattern using MediatR nuget package in .Net 5. The source code is uploaded for your reference.
Happy Coding!!!