The Messaging & CQRS components provide a lightweight, efficient alternative to MediatR using SlimMessageBus, implementing Command Query Responsibility Segregation (CQRS) patterns and event-driven architecture for Domain-Driven Design applications.
The Messaging components implement CQRS patterns that span multiple layers of the Onion Architecture, enabling clean separation between read and write operations:
┌─────────────────────────────────────────────────────────────────┐
│ 🌐 Presentation Layer │
│ (Controllers, API Endpoints) │
│ │
│ Sends: Commands and Queries via IMessageBus │
│ Receives: Results and DTOs from handlers │
└─────────────────────────┬───────────────────────────────────────┘
│
┌─────────────────────────┴───────────────────────────────────────┐
│ 🎯 Application Layer │
│ (Command/Query Handlers, Use Cases) │
│ │
│ 📨 Command Handlers - Write operations (IHandler<TRequest>) │
│ 📊 Query Handlers - Read operations (IQueryHandler<TQuery>) │
│ 🔄 Event Handlers - Cross-cutting concerns │
│ ⚡ Auto-save behavior - EF Core integration │
└─────────────────────────┬───────────────────────────────────────┘
│
┌─────────────────────────┴───────────────────────────────────────┐
│ 💼 Domain Layer │
│ (Entities, Aggregates, Domain Services) │
│ │
│ 🎭 Domain Events - Aggregate communication │
│ 📝 Business Logic - Pure domain operations │
│ 🏷️ No messaging dependencies - Clean separation │
└─────────────────────────┬───────────────────────────────────────┘
│
┌─────────────────────────┴───────────────────────────────────────┐
│ 🗄️ Infrastructure Layer │
│ (Message Bus, Event Dispatching) │
│ │
│ 🚌 SlimMessageBus - Message routing and delivery │
│ 📡 Event Publishers - Domain event dispatching │
│ 🗄️ DbContext Integration - Automatic change persistence │
└─────────────────────────────────────────────────────────────────┘
IWitResponse<T>
, INoResponse
)IWitResponse<T>
, IWitPageResponse<T>
)// Command definition
public record CreateOrderCommand(Guid CustomerId, List<OrderItem> Items)
: Fluents.Requests.IWitResponse<Result<Guid>>;
// Command handler
public class CreateOrderHandler : Fluents.Requests.IHandler<CreateOrderCommand, Result<Guid>>
{
public async Task<IResult<Result<Guid>>> Handle(CreateOrderCommand command)
{
// Business logic here
// Auto-save handled by EfAutoSavePostProcessor
}
}
// Query definition
public record GetCustomerOrdersQuery(Guid CustomerId, int Page, int PageSize)
: Fluents.Queries.IWitPageResponse<OrderSummaryDto>;
// Query handler
public class GetCustomerOrdersHandler : Fluents.Queries.IPageHandler<GetCustomerOrdersQuery, OrderSummaryDto>
{
public async Task<IPagedList<OrderSummaryDto>> Handle(GetCustomerOrdersQuery query)
{
// Optimized read logic here
}
}
// Domain event
public record OrderCreatedEvent(Guid OrderId, Guid CustomerId, decimal TotalAmount);
// Event handler
public class OrderCreatedEventHandler : IEventHandler<OrderCreatedEvent>
{
public async Task Handle(OrderCreatedEvent evt)
{
// Cross-cutting concerns (notifications, logging, etc.)
}
}