Search code examples
masstransit

How to publish a specific event from an implemented interface


Full code (github)...

I'm moving from MediatR to MassTransit to publish my domain events to a queue.

I'm using an interface IDomainEvent in different domain events that implement such interface (in this case PersonCreated and PersonPositionCreated). Then I have an entity 'Person' with a list of IDomainEvent in which I register all the domain events occurred. I Also have a consumer for each specific event.

After persist my entity, I want to iterate all the events of the entity and publish them to the queue.

// Event interface.
public class IDomainEvent
{
}

// Events.
public class PersonCreated : IDomainEvent
{
    public int Id { get; set; }
}

public class PersonPositionCreated : IDomainEvent
{
    public string Position { get; set; }
}

// Entity.
public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Position { get; set; }

    public List<IDomainEvent> Events { get; set; };
}

// Consumers.
public class PersonCreatedConsumer : IConsumer<PersonCreated>
{
    public Task Consume(ConsumeContext<PersonCreated> context)
    {
        Debug.Print(context.Message.Id.ToString());
        return Task.CompletedTask;
    }
}

public class PersonPositionCreatedConsumer : IConsumer<PersonPositionCreated>
{
    public Task Consume(ConsumeContext<PersonPositionCreated> context)
    {
        Debug.Print(context.Message.Position);
        return Task.CompletedTask;
    }
}

// My command.
//...

// Creates Person.
Person person = new Person(){ Id = 1, Name = "Alice", Position = "Developer" };
// Registers the events to the list.
person.Events.Add(new PersonCreated() { Id = person.Id });
person.Events.Add(new PersonPositionCreated() { Position = person.Position });

foreach (IDomainEvent personEvent in person.Events)
{
    // This way, it publish an IDomainEvent and I don't want to use a IConsumer<IDoaminEvent> because I need specific consumers.
    // How can I tell the bus that I sending the specific event and not the IDomainEvent?
    //(I know that inside the iteration I'm dealing with IDomainEvent but it have access to the class that implement the interface).
    // NOTE: That way works with MediatR specific handlers.

      | |
    \    /
     \  /
      \/
    
    _bus.Publish(personEvent);
}

// Of course this two lines works!
//_bus.Publish<PersonCreated>(new PersonCreated() { Id = 1 });
//_bus.Publish<PersonPositionCreated>(new PersonPositionCreated() { Position  = "Developer" });

//...


How can I tell the bus that I am sending the specific event and not the IDomainEvent? (I know that inside the iteration I'm dealing with IDomainEvent, but it has access to the class that implement the interface).


Solution

  • You should call:

    _bus.Publish((object)personEvent);
    

    By casting it to an object, MassTransit will call GetType() and then publish to the exchange (and ultimately consumer) for the object type (aka, implemented message type).