Introduction
When building modern web applications using ASP.NET Core Web API, one common challenge developers face is managing complex business logic while keeping the code clean, scalable, and easy to maintain.
As applications grow, mixing read and write operations in the same logic can make the system harder to manage. This is where the CQRS (Command Query Responsibility Segregation) pattern becomes very useful.
In simple words, CQRS separates the operations that change data (commands) from the operations that read data (queries).
In this article, you will learn how to implement the CQRS pattern in ASP.NET Core Web API step by step using simple language, real-world examples, and practical understanding.
What is CQRS Pattern?
CQRS stands for Command Query Responsibility Segregation.
It means:
Command → Used to create, update, or delete data
Query → Used to read or fetch data
Instead of using a single model for both reading and writing, CQRS separates them into different models and logic.
Real-life example:
Think of a banking system:
Both operations are different and should be handled separately.
Why Use CQRS in ASP.NET Core Web API?
Using CQRS improves the structure of your application.
Without CQRS:
With CQRS:
This pattern is widely used in scalable enterprise applications.
Basic Structure of CQRS
In a CQRS-based ASP.NET Core application, we usually have:
Commands (Write operations)
Queries (Read operations)
Handlers (Process commands and queries)
Models (Separate for read and write)
This separation helps organize the code better.
Step 1: Create ASP.NET Core Web API Project
Start by creating a new Web API project.
Using CLI:
Or use Visual Studio and select ASP.NET Core Web API with .NET 8.
Step 2: Install MediatR Library
To implement CQRS cleanly, we use MediatR, a popular library for handling requests.
Install package:
MediatR helps us send commands and queries to their respective handlers.
Step 3: Configure MediatR in Program.cs
Add MediatR service:
builder.Services.AddMediatR(typeof(Program));
This registers all handlers automatically.
Step 4: Create Command (Write Operation)
Example: Create a product
public class CreateProductCommand : IRequest
{
public string Name { get; set; }
public decimal Price { get; set; }
}
This command represents data required to create a product.
Step 5: Create Command Handler
public class CreateProductHandler : IRequestHandler<CreateProductCommand, string>
{
public Task Handle(CreateProductCommand request, CancellationToken cancellationToken)
{
// Simulate saving data
return Task.FromResult("Product Created: " + request.Name);
}
}
Handler contains the actual business logic.
Step 6: Create Query (Read Operation)
Example: Get product details
public class GetProductQuery : IRequest
{
public int Id { get; set; }
}
Step 7: Create Query Handler
public class GetProductHandler : IRequestHandler<GetProductQuery, string>
{
public Task Handle(GetProductQuery request, CancellationToken cancellationToken)
{
// Simulate fetching data
return Task.FromResult("Product Details for ID: " + request.Id);
}
}
Step 8: Use CQRS in Controller
[ApiController]
[Route("api/[controller]")]
public class ProductController : ControllerBase
{
private readonly IMediator _mediator;
public ProductController(IMediator mediator)
{
_mediator = mediator;
}
[HttpPost]
public async Task<IActionResult> Create(CreateProductCommand command)
{
var result = await _mediator.Send(command);
return Ok(result);
}
[HttpGet]
public async Task<IActionResult> Get(int id)
{
var result = await _mediator.Send(new GetProductQuery { Id = id });
return Ok(result);
}
}
Now controller becomes clean and simple.
Step 9: Real-World Example
In an e-commerce app:
Commands:
Add product
Update product
Delete product
Queries:
Get product list
Get product details
This separation helps scale read and write operations independently.
Common Mistakes to Avoid
Mixing command and query logic
Not using handlers properly
Overcomplicating small applications
Advantages of CQRS Pattern
Disadvantages of CQRS Pattern
When Should You Use CQRS?
Use CQRS when:
Avoid when:
Summary
CQRS pattern in ASP.NET Core Web API helps separate read and write operations, making applications more structured, scalable, and maintainable. By using tools like MediatR and following a step-by-step implementation, developers can build clean and efficient APIs. While it may add some complexity, the long-term benefits make it a powerful pattern for modern application development.