Fundamente și Arhitectură CQRS în .NET

  • Doru Bulubasa
  • 02 July 2025

CQRS (Command Query Responsibility Segregation) este un pattern arhitectural care împarte responsabilitățile aplicației între două zone clar definite:

  • Comenzi (Commands) — modifică starea aplicației (ex: adaugă un articol)

  • Interogări (Queries) — doar citesc datele, fără efecte secundare

Această separare aduce claritate în cod, permite validări mai precise și pregătește aplicația pentru scalabilitate și extensibilitate.


1️⃣ Ce este CQRS?

La bază, CQRS propune să nu mai folosim aceleași obiecte și servicii pentru a citi și scrie date. În schimb, separăm complet:

  • ✏️ Comenzile – cereri care modifică starea (ex: CreatePost, UpdateUser, DeleteInvoice)

  • 🔍 Interogările – cereri care doar citesc informația (ex: GetPostById, SearchUsers, ListInvoices)

📌 Beneficii cheie

Beneficiu

Explicație

🔄 Separare clară

Codul de scriere este izolat de cel de citire – mai ușor de înțeles, testat și întreținut

🧪 Validări dedicate

Poți aplica reguli diferite pentru ce se scrie vs. ce se citește

🚀 Scalabilitate facilă

Poți optimiza sau chiar separa infrastructura pentru read și write (ex: DB replicat pentru queries)

⚡ Performanță

Interogările pot folosi DTO-uri ușoare, proiecții sau cache, fără a afecta regulile de business

🔐 Securitate & audit

Comenzile pot declanșa evenimente, loguri sau verificări suplimentare


2️⃣ Structura de proiect recomandată

CQRS funcționează excelent într-o aplicație organizată după principiile DDD (Domain-Driven Design). O astfel de structură promovează separarea responsabilităților și testabilitatea.

📁 Structură pe layere:

/MyApp
├── MyApp.API               → Punctul de intrare (API, Blazor UI etc.)
├── MyApp.Application       → Comenzi, interogări, DTO-uri, validări, MediatR
├── MyApp.Domain            → Entități, ValueObjects, Interfețe, reguli de business
├── MyApp.Infrastructure    → Persistență, acces la fișiere, servicii externe


🔍 Detalii pe layere

 MyApp.Application

  • 📦 Aici trăiesc Command-urile și Query-urile

  • ✔️ Contine Handlers, Validators, DTO-uri

  • 🤝 Comunicarea se face prin MediatR: Send(new CreatePostCommand(...))

🧠 MyApp.Domain

  • Definiția modelului de business

  • Entități, ValueObjects, agregate, interfețe (IPostRepository)

  • Nu conține referințe către infrastructură sau MediatR

🧱 MyApp.Infrastructure

  • Implementările pentru interfețele din Domain sau Application

  • ApplicationDbContext (EF Core), Repositories, fișiere, servicii de e-mail, etc.

🌐 MyApp.API / MyApp.UI.Blazor

  • Controlere sau pagini UI

  • Aici se primesc request-urile și se trimit mai departe către Application (prin MediatR)

  • Nu conține logică de business


🧩 Exemplu de flux

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


🏁 Ce urmează

În următorul articol, vom construi primul Command complet: CreatePostCommand, cu handler, validare, mapare și salvare în bază de date. Vom introduce MediatR și FluentValidation și vom vedea cum această abordare aduce claritate și extensibilitate.

Scrie un comentariu

Adresa de mail nu va fi publicata. Campurile obligatorii sunt marcate cu *