Skip to main content
Version: 3.2.0

Wolverine

Overview

RCommon.Wolverine integrates WolverineFx as a distributed event handler for the RCommon event handling pipeline. It is focused on event production and subscription rather than the request-response mediator pattern.

The package provides:

  • WolverineEventHandlingBuilder / IWolverineEventHandlingBuilder — registers Wolverine-based subscribers through the RCommon fluent builder.
  • PublishWithWolverineEventProducer — publishes events to all Wolverine handlers using IMessageBus.PublishAsync (fan-out).
  • SendWithWolverineEventProducer — sends events to a single Wolverine handler using IMessageBus.SendAsync (point-to-point).
  • WolverineEventHandler<TEvent> — bridges Wolverine's message dispatch to RCommon's ISubscriber<TEvent> abstraction.

Events must implement ISerializableEvent (from RCommon.Models) to flow through the Wolverine producers.

Installation

NuGet Package
dotnet add package RCommon.Wolverine

This package depends on RCommon.Core and WolverineFx. Wolverine itself requires host-level setup via UseWolverine() on the application host builder — see the Wolverine documentation for transport and endpoint configuration.

Configuration

Wolverine is configured at the host level and within the RCommon builder. Register the Wolverine host extension on the application host builder, then wire up RCommon subscribers.

using RCommon;
using RCommon.Wolverine;
using Wolverine;

var builder = WebApplication.CreateBuilder(args);

// Configure Wolverine at the host level
builder.Host.UseWolverine(opts =>
{
// Configure transports, endpoints, and discovery here
opts.Discovery.IncludeAssembly(typeof(Program).Assembly);
});

// Configure RCommon with Wolverine event handling
builder.Services.AddRCommon()
.WithEventHandling<WolverineEventHandlingBuilder>(wolverine =>
{
wolverine.Consume<OrderPlacedEvent, OrderPlacedEventHandler>();
wolverine.Consume<OrderShippedEvent, OrderShippedEventHandler>();
});
Consume registers the inbound bridge in one call

In RCommon 3.2.0, Consume<TEvent, TEventHandler>() is the idiomatic verb for an inbound Wolverine consumer: it registers the ISubscriber<TEvent> handler and records the event subscription so the router delivers the message. There is no separate AddProducer<T>() step to pair it with — that is only needed on the outbound side when this service emits an event, via Publish<TEvent>() (fan-out) or Send<TEvent>() (point-to-point). AddSubscriber<TEvent, TEventHandler>() remains as an [Obsolete] alias forwarding to Consume for pre-3.2.0 source compatibility.

Modular composition

WithEventHandling<WolverineEventHandlingBuilder> is a cache-aware sub-builder verb. When multiple modules call it, the cached WolverineEventHandlingBuilder is reused and each module's AddSubscriber<TEvent, THandler> and AddProducer<T> registrations accumulate on the same instance. AddProducer<T> deduplicates by concrete producer type, so the same producer registered from two modules yields exactly one descriptor. Note that the host-level builder.Host.UseWolverine(...) call must happen exactly once in the application host; only the RCommon sub-builder participates in module-level composition. See Modular Composition for the full conflict matrix.

Usage

Defining an event

Events dispatched through Wolverine must implement ISerializableEvent:

using RCommon.Models.Events;

public class OrderPlacedEvent : ISerializableEvent
{
public OrderPlacedEvent(Guid orderId, Guid customerId, DateTime placedAt)
{
OrderId = orderId;
CustomerId = customerId;
PlacedAt = placedAt;
}

public Guid OrderId { get; }
public Guid CustomerId { get; }
public DateTime PlacedAt { get; }
}

Creating a subscriber

Implement ISubscriber<TEvent> from RCommon.EventHandling.Subscribers. This is the same interface used by MediatR subscribers — the Wolverine adapter bridges message dispatch to it automatically through WolverineEventHandler<TEvent>.

using RCommon.EventHandling.Subscribers;

public class OrderPlacedEventHandler : ISubscriber<OrderPlacedEvent>
{
private readonly IEmailService _emailService;

public OrderPlacedEventHandler(IEmailService emailService)
{
_emailService = emailService;
}

public async Task HandleAsync(OrderPlacedEvent @event, CancellationToken cancellationToken = default)
{
await _emailService.SendOrderConfirmationAsync(@event.CustomerId, @event.OrderId, cancellationToken);
}
}

Registration

Register subscribers using the IWolverineEventHandlingBuilder extension method. Each call records the event-to-producer subscription in the EventSubscriptionManager so the router only delivers the event to the producers registered for it.

builder.Services.AddRCommon()
.WithEventHandling<WolverineEventHandlingBuilder>(wolverine =>
{
wolverine.Consume<OrderPlacedEvent, OrderPlacedEventHandler>();
});

If you need to construct the subscriber with a factory delegate:

wolverine.Consume<OrderPlacedEvent, OrderPlacedEventHandler>(
sp => new OrderPlacedEventHandler(sp.GetRequiredService<IEmailService>()));

Producing events

Declare each event this service emits with Publish<TEvent>() for fan-out delivery (all subscribers receive the event) or Send<TEvent>() for point-to-point delivery (one handler). These verbs auto-register the matching producer (PublishWithWolverineEventProducer / SendWithWolverineEventProducer) and record the route with EventSubscriptionManager, so there is no need for a raw services.AddScoped<IEventProducer, T>() call:

builder.Services.AddRCommon()
.WithEventHandling<WolverineEventHandlingBuilder>(wolverine =>
{
// Fan-out: all subscribed handlers receive the event
wolverine.Publish<OrderPlacedEvent>();

// Point-to-point: only one handler receives the event
// wolverine.Send<OrderPlacedEvent>();
});

Produce events through RCommon's IEventBus or by raising domain events that flow through the event router — the producers are invoked by the routing infrastructure automatically.

API Summary

IWolverineEventHandlingBuilder extension methods

MethodDescription
AddSubscriber<TEvent, TEventHandler>()Registers TEventHandler as a scoped ISubscriber<TEvent> and records the subscription in the EventSubscriptionManager.
AddSubscriber<TEvent, TEventHandler>(Func<IServiceProvider, TEventHandler>)Same as above, but uses a factory delegate to construct the subscriber.

PublishWithWolverineEventProducer

MemberDescription
ProduceEventAsync<T>(T, CancellationToken)Calls IMessageBus.PublishAsync<T> to deliver the event to all Wolverine handlers subscribed to T. Skips delivery if the event type is not subscribed to this producer.

SendWithWolverineEventProducer

MemberDescription
ProduceEventAsync<T>(T, CancellationToken)Calls IMessageBus.SendAsync<T> to deliver the event to a single Wolverine handler. Skips delivery if the event type is not subscribed to this producer.

WolverineEventHandler<TEvent>

MemberDescription
HandleAsync(TEvent, CancellationToken)Called by Wolverine's message dispatch infrastructure. Delegates to the injected ISubscriber<TEvent>.

Key interfaces and base types

TypePackageDescription
IWolverineEventHandlingBuilderRCommon.WolverineBuilder interface for configuring Wolverine event handling. Extends IEventHandlingBuilder.
WolverineEventHandlingBuilderRCommon.WolverineDefault implementation. Constructed by WithEventHandling<WolverineEventHandlingBuilder>.
ISerializableEventRCommon.ModelsMarker interface required on all events dispatched through Wolverine producers.
ISubscriber<TEvent>RCommon.EventHandlingApplication-level handler interface. Implement this for your event handling logic.
IWolverineEventHandler<TEvent>RCommon.WolverineWolverine-facing handler interface implemented by WolverineEventHandler<TEvent>.
RCommonRCommon