Search code examples
genericshandlersrebus

Rebus: How to handle event types with generics


I'm having some trouble with my handlers not "catching" my events. My current structure is that I have a wrapper around Rebus in a separate package that wraps around Rebus' methods and expose a factory to use with i.e. Autofac - so far so good.

I then have all my domain events in separate packages and namespaces so they don't know about Rebus and vice versa. he all derive from the type IDistributedEvent and implements the abstract type DistributedEvent.

When I publish an event, say MessageSent, I then in my wrapper make an envelope event BusEvent where I set the domain event as a Payload property:

public Task Publish<T>( T payload, TimeSpan expiration ) where T : IDistributedEvent
{
    var message = new BusEvent<T> { Payload = payload };
    return InternalBus.Publish( message, new Dictionary<string, string> {
        { Headers.TimeToBeReceived, expiration.ToString() },
        { "pd-version", payload.EventVersion.ToString() },
    } );
}

The reason for this is to be able to add some metadata over time (But maybe this is the wrong way of doing this).

Anyway, my problem is now that my handlers is no recognised as a handler that can handle the type BusEvent<MessageSent>, even though I create handlers using the interface IHandleMessages<BusEvent<T>> where T : IDistributedEvent

So the question is: Am I doing it wrong here, or is this simply just a bad way of doing it. Thus, I should just remove the enveloping type and handle the domain event type directly?


Solution

  • If I were you, I would ditch the envelope thing – Rebus already has a mechanism in place that allows for attaching headers to messages when you send them, so you can add custom things already if you like.

    The limitation of course is that your extra data needs to be representable as string-string key-value pairs, but then again: JSON is a string, so anything is possible ;)

    I don't see any reason though why it should not work with your homemade generic envelope – if your handlers are registered as the correct IHandleMessages<BusEvent<YourMessage>> when the sent message is a YourMessage, it should work just fine.

    Is it because you expect the polymorphic dispatch to work with a generic handler implementing IHandleMessages<BusEvent<T>> where T : IDistributedEvent? Because then it won't work, because receiving a message of the type BusEvent<MessageSent> would result in looking up the following handlers in Autofac:

    IHandleMessages<BusEvent<MessageSent>>
    IHandleMessages<object>
    

    because that's what Rebus finds when it looks up the inheritance chain starting with BusEvent<>, but obviously that does not include

    IHandleMessages<BusEvent<DistributedEvent>>
    

    or

    IHandleMessages<BusEvent<IDistributedEvent>>