Skip to main content

Publisher Channels Overview

Hermodr ships ready-made channel implementations for the most common messaging transports, plus reliability-oriented publisher extensions such as the transactional outbox and dead-letter replay. You install only what you need and register the pieces in the EventPublisherBuilder chain.

Available channels and reliability extensions

FeaturePackageBest for
Azure Service BusHermodr.Publisher.AzureServiceBusCloud-native apps on Azure, reliable queue- or topic-based delivery
RabbitMQHermodr.Publisher.RabbitMqOn-premise or self-hosted AMQP broker, fine-grained routing
MassTransitHermodr.Publisher.MassTransitProjects already using MassTransit; broker-agnostic
WebhookHermodr.Publisher.WebhookDelivering events to external HTTP endpoints with HMAC signing
Publish Error HandlingHermodr.PublisherCross-cutting interception of publish failures for logging, policy, auditing, and custom recovery
OpenTelemetry InstrumentationHermodr.Publisher.OpenTelemetryDistributed tracing with W3C trace context propagation across service boundaries
Transactional OutboxHermodr.Publisher.OutboxGuaranteed at-least-once delivery via a transactional outbox table
Dead-Letter Handling and ReplayHermodr.Publisher.DeadLetterCapturing failed channel deliveries, persisting them, and replaying them later
Test (in-memory)Hermodr.TestPublisherUnit and integration tests

Multiple channels

You can register more than one channel at a time. The publisher will fan every event out to all registered channels:

builder.Services
.AddEventPublisher(options => options.Source = new Uri("https://myapp.example.com"))
.AddServiceBus(options =>
{
options.ConnectionString = "...";
options.QueueName = "events";
})
.AddWebhooks(options =>
{
options.EndpointUrl = "https://partner.example.com/events";
options.SigningSecret = "s3cr3t";
});

Named channels

When two or more channels of the same transport type are registered simultaneously, assign each a logical name via the ChannelName property on its options. At publish time, target the right channel by name using the convenience extension methods or by setting ChannelName on the per-call options:

builder.Services
.AddEventPublisher()
.AddRabbitMq(opts => { opts.ChannelName = "rabbit-orders"; opts.ExchangeName = "orders"; })
.AddRabbitMq(opts => { opts.ChannelName = "rabbit-notifications"; opts.ExchangeName = "notifications"; });

// Publish only to the "rabbit-orders" channel
await publisher.PublishAsync(orderPlaced, channelName: "rabbit-orders");

See Named Channels for the full guide.

Typed channels

Every built-in channel supports a typed registration variant (AddRabbitMq<TEvent>(), AddServiceBus<TEvent>(), AddMassTransit<TEvent>(), AddWebhooks<TEvent>()) that routes only events of the specified data class to that channel. Typed channels also support a two-level options hierarchy — a base set of defaults merged with per-event-type overrides — so you can share common settings and specialise only what differs.

builder.Services
.AddEventPublisher()
.AddRabbitMq(opts => { opts.ConnectionString = "amqp://..."; opts.ExchangeName = "events"; })
.AddRabbitMq<OrderPlacedData>(opts => { opts.ExchangeName = "orders"; opts.QueueName = "order-placed"; });

See Typed Channels for the full guide.

Implementing a custom channel

See Publish Channels for instructions on creating and registering your own IEventPublishChannel or IEventPublishChannel<TEvent>.