CQRS Pattern in .NET Core

Optimizing Application Architecture with CQRS Pattern in .NET Core

Ali Zia
Virtual Force Inc.
Published in
3 min readOct 30, 2023

--

Command Query Responsibility Segregation (CQRS) is a software architectural pattern that separates the logic into two parts: commands (write operations) and queries (read operations). In this article, we will explore how to implement CQRS in a .NET Core application.

So, let’s explain CQRS two parts:
1. Commands: Where we can modify the application state. These operations typically include creating, updating, or deleting data.

2. Queries: Responsible for retrieving data from the application state. These operations are read-only and do not modify the application’s state.

Setting Up a .NET Core Project

Before implementation CQRS, let’s set up a .NET Core project using the command-line interface (CLI):

dotnet new web -n MyCQRSApp cd MyCQRSApp

Implementing CQRS in .NET Core :

  1. Define Commands and Queries:
    Create commands and queries as separate models that representing write and read operations accordingly.
public class CreateProductCommand {
public string Name { get; set; }
public decimal Price { get; set; }
}

public class GetProductQuery {
public int ProductId { get; set; }
}

2. Implement Command and Query Handlers:
Now, create handlers for commands and queries to execute the logic.

public interface ICommandHandler<TCommand> {
void Handle(TCommand command);
}

public interface IQueryHandler<TQuery, TResult> {
TResult Handle(TQuery query);
}

public class ProductCommandHandler : ICommandHandler<CreateProductCommand> {
public void Handle(CreateProductCommand command) {
// Logic to handle the create product command
}
}

public class ProductQueryHandler : IQueryHandler<GetProductQuery, Product> {
public Product Handle(GetProductQuery query) {
// Logic to handle the get product query and return the product return new Product();
}
}

3. Define Product Model:
Create a model for the product.

public class Product {
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}

4. Configure Dependency Injection:
Configure the DI in startup.cs file. Register the command and query handlers in the DI container.

public void ConfigureServices(IServiceCollection services) {
// Register command handlers services.AddScoped<ICommandHandler<CreateProductCommand>, ProductCommandHandler>();
// Register query handlers services.AddScoped<IQueryHandler<GetProductQuery, Product>, ProductQueryHandler>();
// Add other configurations
}

5. Use CQRS in Controllers:
In the controller class, inject the necessary handlers and use them to execute commands and queries.

[ApiController]
[Route("api/products")]
public class ProductController : ControllerBase {

private readonly ICommandHandler<CreateProductCommand> _createCommandHandler;
private readonly IQueryHandler<GetProductQuery, Product> _queryHandler;

public ProductController( ICommandHandler<CreateProductCommand> createCommandHandler, IQueryHandler<GetProductQuery, Product> queryHandler) {
_createCommandHandler = createCommandHandler;
_queryHandler = queryHandler;
}

[HttpPost]
public IActionResult CreateProduct([FromBody] CreateProductCommand command) {

_createCommandHandler.Handle(command);
return Ok("Product created successfully");
}

[HttpGet("{productId}")]
public IActionResult GetProduct(int productId) {

var query = new GetProductQuery { ProductId = productId }
var product = _queryHandler.Handle(query); return Ok(product);
}
}

Final Thoughts:

To implement CQRS in a .NET Core application, you need to divide your code into two parts: commands (for making changes) and queries (for reading data). You define models for these commands and queries and create handlers to process them. You also configure dependency injection to manage these handlers. After that, keep write and read operations separate, which can improve your app’s scalability and maintainability.

You can use this guide as a foundation and implement your CQRS setup to meet your application requirements.

--

--

Ali Zia
Virtual Force Inc.

Software Engineer. Developer. System Designer | Currently leading a fintech project. Writing: technical documents.