LiteBus
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());
}
APIRole
ICommand<TResult> with generic message typeGeneric command contract
IQuery<TResult> / IStreamQuery<TResult> with generic message typeGeneric query contract
IEvent or typed plain event with generic payloadGeneric event contract
RegisterFromAssembly(...) on semantic buildersRegisters 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.Abstractions
  • LiteBus.Queries / LiteBus.Queries.Abstractions
  • LiteBus.Events / LiteBus.Events.Abstractions
  • LiteBus.Messaging

Requires

  • mediator.module-registration
  • mediator.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 methodProject
Send_LogActivityCommand_ShouldGoThroughHandlersCorrectlyLiteBus.Mediator.UnitTests
Mediating_GetProductByCriteriaQuery_ShouldGoThroughHandlersCorrectlyLiteBus.Mediator.UnitTests
mediating_generic_event_goes_through_registered_handlers_correctlyLiteBus.Mediator.UnitTests
Mediating_StreamQuery_WithIndirectHandler_ShouldUseBaseTypeHandlerLiteBus.Mediator.UnitTests
Register_ClosedGenericHandlers_ShouldKeepIndependentDescriptorsLiteBus.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.

Deep Docs

On this page