Follow us

CQRS Pattern With MediatR in .Net Core

 

CQRS(Command Query Responsibility Segregation) Pattern, where you create two different stream for data processing i.e. one for all DML i.e. data post/write actions through command and another one is DQL i.e. read/select actions which is with query.

 

Use cases when/where to use?

  • Where your database related changes happening frequently then, its better to separate, so that one change could not impact other.
  • When your database having lots of load and you might be interested to distribute read and write to different database, so in that case you might need to host your read and write app separately and point to different database.
  • When you have some crucial write operations and you do not want to handover to all the devs to work on in it but all devs can work on read operations.

 

For this demo, I used "MediatR" pckage, so what is "MediatR"?

The mediator design pattern controls how a set of objects communicate and helps to reduce the number of dependencies among these objects that you must manage. In the mediator design pattern, objects don’t communicate with one another directly, but through a mediator.

It supports request/response, commands, queries, notifications and events, synchronous and async with intelligent dispatching via C# generic variance.

 

With below example if you see for two get and add class i.e. "GetTodoById.cs" and "AddTodo.cs" I do not require to inject DI into startup.cs while I am using into TodoController, instead it is getting managed by MediatR DI I added into startup.cs and my both class implementing MediatR.

 

I have repository class which will return some fixed list of items with Todos porperty:

3 
7 
8 
9 
le 
11 
13 
14 
16 
17 
CQRSTest. Domain; 
using Generic; 
CQRSTest. Database 
namespace 
public class Repository 
public List<Tod0> Todos { 
get; = new List<Tod0> 
new 
new 
new 
new 
new 
Todo{ld - 
Todo{ld = 2, 
Todo{ld - 
Todo{ld - 
Todo{ld = 5, 
Name — Todoaction 1" , 
Name = "Todo action 2' , 
Name = "Todo action , 
Name — Todoaction 4' , 
Name = "Todo action 5" , 
Cmpleted = false 
Completed = false 
Completed = false 
Completed = 
false 
Completed = false

 

Add "MediatR" packages to solution:

- R , 1 1r0 10 
MediatRExtensions.Microsoft.Dependencyl'dection ; 一 my 1 Md , 
Installed

Created separate folder/file for GetTodoById() (ideally, it will go into defferent solution to have all select/read related stuff as part of CQRS pattern, but just for demo, I just created separate file):

le 
11 
12 
13 
14 
16 
17 
18 
19 
2e 
22 
23 
24 
26 
27 
28 
29 
3e 
33 
37 
38 
O referen ces 
public static class GetTodoById 
// Query / Command 
// All the data we need to execute 
Query(int Id) : 
public record 
// Handler 
// All the business logic to execute. Returns a response. 
I reference 
public class Handler : IRequestHandler<Query, Response) 
private readonly Repository repository; 
O references 
public Handler(Repository repository) 
repository repository; 
this. 
O references 
public async Task<Response> Handle(Querv request, CancellationToken cancellationToken) 
var todo = repository. Todos.FirstOrDefau1t(x x.ld request.ld); 
todo null"? null 
: new todo.Name, todo.completegy•, 
tur 
// Response 
l/' The data we want to return 
public record Response(int Id, 
string Name, 
bool Completed);

 

Created separate folder/file for AddTodo() (ideally, it will go into different solution to have all select/read related stuff as part of CQRS pattern, but just for demo, I just created separate file):

12 
13 
IS 
16 
19 
21 
22 
23 
23 
26 
27 
29 
3e 
31 
32 
O references 
public static class AddTodo 
// Cormand 
• C QRS 
IRequest<int>; 
public record 
Comand(string Name) . 
// Handler 
I reference 
public class Handler : IRequestHandler<Corrmand, 
private readonly Repository repository; 
O references 
public Handler(Repository repository) 
repository repository; 
this. 
int > 
public async Handle(Conmand request, CancellationToken cancellationToken) 
repository .Todos.Add(new Todo Id = le. Name = request.Name 
return 10;

 

Created controller to use both get and add Todo:

[Apicontrollerl 
public class TodoContr011er : ControllerBase 
private readonly Imediator 
public TodoContr011er(IMediator mediator) 
this .mediator mediator; 
public async GetTod03yId(int id) 
response = await 
mediator. Send(new GetTodoById. Query(id)) ; 
var 
—z null ? NotFound() : Ok(response) ; 
return 
response — 
O references 
Conrnand mediator.

 

Added DI to startup.cs for MediatR and repository class:

using Microsoft.OpenApi.Mode1s; 
CQRSTest 
namespace 
3 references 
public class Startup 
public Startup(IConfiguration configuration) 
Configuration configuration; 
I reference 
public IConfiguration Configuration { get; 
// This method gets called by the runtime. 
O references 
use this method to add services to the co 
public void 
ConfigureSeNices(IServiceC011ection services) 
services. AddContr011ers( ) ; 
services .AddSwaggerGen(c 
c. new enApiInfo { Title 
services. AddSing1eton (Repositoryf() ; 
services .AddhediatR(typeof(Startup) . Assembly) ; 
"CQRSTest", 
Version =

 

My swagger result for GetTodoById():

 

 

 

Categories/Tags: cqrs~mediatr

Recent Articles

1

AWS Saving Plan - Cost optimization tips

2
3

AWS RDS Key Concepts & Why you should use it?

4
5

Open-Search/Kibana - Multi Tenancy Setup

See All Articles