RO EN

Foundations and CQRS Architecture in .NET

Foundations and CQRS Architecture in .NET
Doru Bulubasa
02 July 2025

CQRS (Command Query Responsibility Segregation) is an architectural pattern that divides the application's responsibilities into two clearly defined areas:

  • Commands — modify the application's state (e.g., add an article)

  • Queries — only read data, without side effects

This separation brings clarity to the code, allows for more precise validations, and prepares the application for scalability and extensibility.


1️⃣ What is CQRS?

At its core, CQRS proposes not to use the same objects and services for reading and writing data. Instead, we completely separate:

  • ✏️ Commands – requests that modify the state (e.g., CreatePost, UpdateUser, DeleteInvoice)

  • 🔍 Queries – requests that only read the information (e.g., GetPostById, SearchUsers, ListInvoices)

📌 Key Benefits

Benefit

Explanation

🔄 Clear separation

Write code is isolated from read code – easier to understand, test, and maintain

🧪 Dedicated validations

You can apply different rules for what is written vs. what is read

🚀 Easy scalability

You can optimize or even separate infrastructure for read and write (e.g., replicated DB for queries)

⚡ Performance

Queries can use lightweight DTOs, projections, or cache without affecting business rules

🔐 Security & audit

Commands can trigger events, logs, or additional checks


2️⃣ Recommended project structure

CQRS works excellently in an application organized according to the principles of DDD (Domain-Driven Design). Such a structure promotes separation of responsibilities and testability.

📁 Layered structure:

/MyApp
├── MyApp.API               → Entry point (API, Blazor UI etc.)
├── MyApp.Application       → Commands, queries, DTOs, validations, MediatR
├── MyApp.Domain            → Entities, ValueObjects, Interfaces, business rules
├── MyApp.Infrastructure    → Persistence, file access, external services


🔍 Layer details

 MyApp.Application

  • 📦 Here live the Commands and Queries

  • ✔️ Contains Handlers, Validators, DTOs

  • 🤝 Communication is done through MediatR: Send(new CreatePostCommand(...))

🧠 MyApp.Domain

  • Definition of the business model

  • Entities, ValueObjects, aggregates, interfaces (IPostRepository)

  • Does not contain references to infrastructure or MediatR

🧱 MyApp.Infrastructure

  • Implementations for interfaces from Domain or Application

  • ApplicationDbContext (EF Core), Repositories, files, email services, etc.

🌐 MyApp.API / MyApp.UI.Blazor

  • Controllers or UI pages

  • Here requests are received and forwarded to Application (via MediatR)

  • Does not contain business logic


🧩 Example flow

HTTP POST /api/posts
       ↓
[API Controller] → CreatePostCommand → MediatR
       ↓
[CommandHandler] → Domain → Repository → DbContext.SaveChanges()


🏁 What’s next

In the next article, we will build the first complete Command: CreatePostCommand, with handler, validation, mapping, and saving to the database. We will introduce MediatR and FluentValidation and see how this approach brings clarity and extensibility.