IHandlerRegistry
Overview
Section titled “Overview”IHandlerRegistry is a marker interface with no members. Its sole purpose is to give the dependency-injection container a well-known type to query at startup. The framework resolves every registered IHandlerRegistry implementation eagerly during bus initialisation. Because DI resolution runs the constructor, implementations can encode validation logic there — verifying that all expected message handlers are present — and fail startup loudly rather than failing silently at first-message delivery.
Most consumers of ServiceConnect never need to implement this interface. It is documented here for completeness and for teams that want to add startup-time consistency checks to their handler bindings.
See Handlers for the broader handler model.
Reference
Section titled “Reference”IHandlerRegistry has no members. It is a marker used during startup to trigger eager resolution of implementations, which validates handler configuration early rather than at first-message delivery. The full source is:
namespace ServiceConnect.Interfaces;
/// <summary>/// Marker interface for internal handler registries that need eager initialization./// Implementations are resolved during startup to trigger validation of handler configurations./// </summary>public interface IHandlerRegistry{}Implementing
Section titled “Implementing”Eager initialisation
Section titled “Eager initialisation”The DI container resolves all IHandlerRegistry implementations at bus startup, before any message is consumed. If a constructor throws, startup fails immediately with a clear exception. This surfaces misconfigured handler bindings — missing registrations, wrong scope, incorrect type mappings — as a hard start-up error rather than an intermittent runtime failure.
Typical content
Section titled “Typical content”Implementations hold no persistent state beyond the validation logic executed in their constructor. A typical implementation receives an IServiceProvider through dependency injection and uses it to verify that the expected IMessageHandler<T> types are present. If any are missing, the constructor throws a descriptive exception.
Because construction is single-threaded during startup, thread-safety inside the constructor is not a concern.
Startup validation registry
Section titled “Startup validation registry”The following example registers a handler registry that inspects the IServiceProvider on startup and fails fast if any IMessageHandler<T> required by the order processing pipeline is absent.
using Microsoft.Extensions.DependencyInjection;using ServiceConnect.Interfaces;
public sealed class StartupValidatingHandlerRegistry : IHandlerRegistry{ private static readonly Type[] RequiredHandlers = [ typeof(IMessageHandler<OrderPlaced>), typeof(IMessageHandler<PaymentAuthorised>), typeof(IMessageHandler<ShipmentDispatched>), ];
public StartupValidatingHandlerRegistry(IServiceProvider services) { var missing = RequiredHandlers .Where(t => services.GetService(t) is null) .Select(t => t.Name) .ToList();
if (missing.Count > 0) throw new InvalidOperationException( "The following message handlers are required but not registered: " + string.Join(", ", missing)); }}Register it during bus startup:
services.AddServiceConnect(builder =>{ builder.UseRabbitMQ(transport => transport.Host = "rabbit.internal.example"); builder.AddRegistration(svc => svc.AddSingleton<IHandlerRegistry, StartupValidatingHandlerRegistry>());});When the bus starts, the framework resolves StartupValidatingHandlerRegistry, which runs the constructor. If OrderService forgot to register its ShipmentDispatched handler, startup throws an InvalidOperationException immediately — before any connection to the broker is made and before the service starts accepting traffic.
HandlerInterfaceKind enum
Section titled “HandlerInterfaceKind enum”HandlerInterfaceKind discriminates which handler interface a HandlerReference was produced for. A single class that implements multiple handler interfaces produces one HandlerReference per interface, each carrying the appropriate Kind.
namespace ServiceConnect.Interfaces;
public enum HandlerInterfaceKind{ /// <summary> /// The handler implements <see cref="IMessageHandler{TMessage}"/>. /// </summary> MessageHandler,
/// <summary> /// The handler implements <see cref="IProcessHandler{TData,TMessage}"/>. /// </summary> ProcessHandler,
/// <summary> /// The handler implements <see cref="IStreamHandler{TMessage}"/>. /// </summary> StreamHandler,
/// <summary> /// The handler extends <see cref="Aggregator{TMessage}"/>. /// </summary> Aggregator,}Custom IHandlerRegistry implementations and callers that inspect the registry’s HandlerReference list use this enum to discriminate which handler interface a reference was produced for — for example, to apply different dispatch logic for ProcessHandler references versus MessageHandler references, or to filter the list to only Aggregator references when querying aggregator state.
See also
Section titled “See also”- Handlers — the handler model and registration conventions
IMessageDispatcher— the orchestrator that drives message dispatch at runtimeIMessageProcessor— the chain-of-responsibility hook invoked during dispatch