Skip to main content

Event Subscriptions

The Hermodr.Subscriptions package adds an event dispatcher middleware that routes published CloudEvent instances to matching subscriber handlers.

Overview

Subscriptions are evaluated by one or more IEventSubscriptionResolver implementations. The built-in EventSubscriptionRegistry keeps subscriptions in memory, but resolvers can read from any source — a local store, a relational database, a remote subscription service, or any combination. In future releases, subscription evaluation may even be delegated entirely to a remote system.

Why Use Subscriptions?

  • Fan-out within an application — notify multiple services without a broker.
  • Integration testing — assert that specific events are handled without external infrastructure.
  • Side-effects on publish — trigger audit logging, cache invalidation, or read-model projection.
  • Event routing — conditionally re-publish events to a different channel based on payload content.
  • Dynamic, database-backed rules — load subscription filters from a store, update them at runtime, and let resolvers pick up the changes without restarting the application.

Architecture Overview

┌─────────────────────────────────────────────────────────────┐
│ Your application │
│ │
│ ┌──────────────┐ ┌────────────────────────────┐ │
│ │ Event data │─────▶│ EventPublisher │ │
│ └──────────────┘ └────────────┬───────────────┘ │
│ │ fan-out │
│ ┌──────────────┴──────────────┐ │
│ │ │ │
│ ┌────────▼────────┐ ┌──────────▼───┐ │
│ │ EventDispatcher │ │ Channel B │ │
│ │ (middleware) │ │ (Azure SB …) │ │
│ └────────┬────────┘ └──────────────┘ │
│ │ resolves matching subscriptions │
│ ┌────────┴──────────────────────────────────┐ │
│ │ IEventSubscriptionResolver (× N) │ │
│ │ ┌──────────────────────────────────────┐ │ │
│ │ │ EventSubscriptionRegistry (default) │ │ │
│ │ │ DatabaseResolver / RemoteResolver … │ │ │
│ │ └──────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
  1. You register resolver/registry services with AddSubscriptions().
  2. AddSubscriptions() also wires EventDispatcher into the publisher pipeline during DI registration.
  3. For each event, the dispatcher queries all IEventSubscriptionResolver instances and aggregates matches.
  4. Every matched subscription's HandleAsync is invoked sequentially.

Quick Start

1. Install the package

dotnet add package Hermodr.Subscriptions

2. Register subscriptions in DI

services.AddEventPublisher()
.AddSubscriptions()
.Subscribe("com.example.order.*", async (cloudEvent, ct) =>
{
Console.WriteLine($"Order event received: {cloudEvent.Type}");
await Task.CompletedTask;
}, name: "log-orders");

3. Publish

var publisher = serviceProvider.GetRequiredService<IEventPublisher>();

await publisher.PublishAsync(new OrderPlaced { OrderId = "42" });
// ↑ "log-orders" subscription fires because "com.example.order.placed" matches "com.example.order.*"

Configure EventDispatcherOptions during registration through AddSubscriptions(options => ...) or subs.ConfigureOptions(...). The legacy UseDispatcher() extension remains for source compatibility but is a no-op.

Pages in This Section

PageDescription
Subscription FiltersEventFilter factory methods, EventFilterBuilder fluent API, envelope attribute filters, data-field filters, and combining expressions
Filter ExpressionsThe FilterExpression model, EventFilter / EventFilterBuilder, FilterExpressionType, evaluator behaviour, serialization, and direct evaluation
Event DispatcherHow the dispatcher works, DI setup, and error handling
Routing SubscriptionsRe-publishing matched events to a different channel
Custom ResolversReading subscriptions from a database or remote service