CQRS Patterns in .NET

Command Query Responsibility Segregation patterns and implementation strategies in .NET applications

Core Concept #

CQRS separates read and write operations into distinct models, optimizing each for their specific concerns.

 1// Command side - optimized for writes
 2public class CreateOrderCommand
 3{
 4    public Guid CustomerId { get; set; }
 5    public List<OrderItem> Items { get; set; }
 6}
 7
 8// Query side - optimized for reads
 9public class OrderSummaryQuery
10{
11    public Guid OrderId { get; set; }
12}
13
14public class OrderSummaryView
15{
16    public Guid Id { get; set; }
17    public string CustomerName { get; set; }
18    public decimal Total { get; set; }
19    public string Status { get; set; }
20}

Key Benefits #

  • Performance: Separate optimization strategies for reads vs writes
  • Scalability: Independent scaling of command and query sides
  • Flexibility: Different data models for different use cases
  • Complexity Management: Clear separation of concerns

Common Patterns #

MediatR Implementation #

 1public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, Guid>
 2{
 3    public async Task<Guid> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
 4    {
 5        // Write logic
 6    }
 7}
 8
 9public class OrderSummaryQueryHandler : IRequestHandler<OrderSummaryQuery, OrderSummaryView>
10{
11    public async Task<OrderSummaryView> Handle(OrderSummaryQuery request, CancellationToken cancellationToken)
12    {
13        // Read logic
14    }
15}

Works naturally with Event Sourcing for write models and projections for read models.