IConfiguration vs IOptions NET
Synchronous and Asynchronous in .NET Core
Model Binding and Validation in ASP.NET Core
ControllerBase vs Controller in ASP.NET Core
ConfigureServices and Configure methods
IHostedService interface in .NET Core
ASP.NET Core request processing
| Event Sourcing | Integration with MassTransit or MediatR | |
⚡ CQRS (Command Query Responsibility Segregation) |
Command Query Responsibility Segregation (CQRS) is a design pattern that separates the operations for reading data (queries) from those for updating data (commands). Unlike traditional CRUD (Create, Read, Update, Delete) architectures that use a single model for both, CQRS maintains distinct models, allowing each to be optimized for its specific purpose.
This separation is often implemented with different data stores or different schemas within a single data store. While the write-side (command) model focuses on business logic and data integrity, the read-side (query) model is typically denormalized and optimized for efficient querying and display.
CQRS is a design pattern that separates read operations (queries) from write operations (commands). Instead of using the same model for both, CQRS uses different models optimized for their purpose:
This separation improves scalability, maintainability, and clarity in complex systems.
The MediatR library is commonly used to implement CQRS in .NET Core. It acts as an in-process messaging system that decouples the sending of commands and queries from their respective handlers.
In your ASP.NET Core API project, install the MediatR and MediatR.Extensions.Microsoft.DependencyInjection NuGet packages.
For a clean architecture, organize the command and query logic into separate folders or projects.
- YourProject.Api
- Features
- Products
- Commands
- CreateProduct
- CreateProductCommand.cs
- CreateProductCommandHandler.cs
- Queries
- GetProduct
- GetProductQuery.cs
- GetProductQueryHandler.cs
- DTOs
- ProductDto.cs
A query is a simple data transfer object (DTO) that holds the data needed to retrieve information, and it returns a result without altering state.
// Features/Products/Queries/GetProduct/GetProductQuery.cs
public class GetProductQuery : IRequest<ProductDto?>
{
public Guid Id { get; set; }
}
// Features/Products/DTOs/ProductDto.cs
public record ProductDto(Guid Id, string Name, decimal Price);
This handler contains the specific logic for fetching the data, often projecting it directly to the DTO to avoid fetching unnecessary fields.
A command represents an action that modifies the system's state and typically does not return a value.
This handler contains the business logic for the write operation.
The controller uses MediatR's ISender to dispatch commands and queries.
Using the MediatR library to implement CQRS:
// Install-Package MediatR.Extensions.Microsoft.DependencyInjection
// Command
public record CreateOrderCommand(string OrderId, string Customer) : IRequest<bool>;
// Command Handler
public class CreateOrderHandler : IRequestHandler<CreateOrderCommand, bool>
{
public Task<bool> Handle(CreateOrderCommand request, CancellationToken cancellationToken)
{
Console.WriteLine($"Order Created: {request.OrderId} for {request.Customer}");
return Task.FromResult(true);
}
}
// Query
public record GetOrderByIdQuery(string OrderId) : IRequest<Order>;
// Query Handler
public class GetOrderByIdHandler : IRequestHandler<GetOrderByIdQuery, Order>
{
public Task<Order> Handle(GetOrderByIdQuery request, CancellationToken cancellationToken)
{
return Task.FromResult(new Order { OrderId = request.OrderId, Customer = "Demo Customer" });
}
}
// Model
public class Order
{
public string OrderId { get; set; }
public string Customer { get; set; }
}
CQRS is a powerful architectural pattern for scalable, maintainable, and event-driven systems . In .NET Core, it is often implemented with MediatR and works best in complex domains where read and write workloads differ significantly.
| Event Sourcing | Integration with MassTransit or MediatR | |