CatalogMediator
Generic Messages and Handlers
- ID:
mediator.generic-messages - Name: Generic messages and handlers
- Maturity: GA
- Summary: Supports generic command/query/event message shapes with closed handlers resolved per concrete type.
What It Does
LiteBus supports generic message contracts such as CreateEntityCommand<TEntity, TKey> and matching closed handlers. The registry stores exact descriptors for closed message types, so handlers for GetByIdQuery<Order> and GetByIdQuery<Customer> remain independent. Open constructed handler shapes use a generic-definition descriptor as a fallback when no exact closed descriptor exists.
This enables shared behavior and reduced duplication for repeated CRUD or projection patterns while keeping typed handler contracts.
Public Surface
public sealed record GetByIdQuery<TEntity>(Guid Id) : IQuery<TEntity>;
public sealed class GetByIdQueryHandler<TEntity> : IQueryHandler<GetByIdQuery<TEntity>, TEntity>
where TEntity : class, new()
{
public Task<TEntity> HandleAsync(GetByIdQuery<TEntity> query, CancellationToken cancellationToken = default)
=> Task.FromResult(new TEntity());
}| API | Role |
|---|---|
ICommand<TResult> with generic message type | Generic command contract |
IQuery<TResult> / IStreamQuery<TResult> with generic message type | Generic query contract |
IEvent or typed plain event with generic payload | Generic event contract |
RegisterFromAssembly(...) on semantic builders | Registers generic messages/handlers discovered in assembly |
MessageRegistry.Find(Type) | Resolves an exact closed descriptor before an open generic-definition fallback |
Packages
LiteBus.Commands/LiteBus.Commands.AbstractionsLiteBus.Queries/LiteBus.Queries.AbstractionsLiteBus.Events/LiteBus.Events.AbstractionsLiteBus.Messaging
Requires
mediator.module-registrationmediator.polymorphic-dispatch
Invariants
- Generic message handlers must still satisfy single-handler rule for command/query.
- Generic constraints control valid concrete message-handler combinations.
- Closed generic handler registrations never share a direct message descriptor.
- Open generic definitions remain fallback templates for compatible closed messages.
Non-Goals
- Auto-generation of generic CRUD message families.
- Schema registry for generic type evolution.
- Durable open generic contract registration without closed type selection.
Observability
No dedicated telemetry for generic message closing or dispatch is exposed.
Operational alternatives:
- Use handler-level logs with concrete
typeof(T)metadata. - Validate coverage through integration and unit tests for representative closed types.
Test Coverage
Covered
| Test method | Project |
|---|---|
Send_LogActivityCommand_ShouldGoThroughHandlersCorrectly | LiteBus.Mediator.UnitTests |
Mediating_GetProductByCriteriaQuery_ShouldGoThroughHandlersCorrectly | LiteBus.Mediator.UnitTests |
mediating_generic_event_goes_through_registered_handlers_correctly | LiteBus.Mediator.UnitTests |
Mediating_StreamQuery_WithIndirectHandler_ShouldUseBaseTypeHandler | LiteBus.Mediator.UnitTests |
Register_ClosedGenericHandlers_ShouldKeepIndependentDescriptors | LiteBus.Mediator.UnitTests |
Untested
- Deeply nested generic arguments in stream query scenarios.
- Generic event publish with high parallel handler counts and aggregate failures.
Out-of-Scope
- Durable contract migration strategy for many closed generic message variants.
- Compile-time code generation for generic mediator contracts.