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.