Search code examples
c#masstransitconsumer

How to pass IBus to masstransit consumer constructor


Good day

I'm registering masstransit consumer this way:

var provider = services.BuildServiceProvider();

cfg.ReceiveEndpoint(RabbitMqOptions.StatusChangeQueueName, e =>
{
e.Consumer(() => new ConsumerProcessingStatusChange(provider));
});

and want my consumer to Publish to another exchange is there a way to get IBus from service provider in consumer constructor? or should I pass other parameter (which one?)

public class ConsumerProcessingStatusChange : IConsumer<***>
    {
        private readonly IBus _bus;
        private readonly IMapper _mapper;

        public ConsumerProcessingStatusChange(IServiceProvider provider)
        {
            _bus = provider.GetService<IBus>();
            _mapper = new MapperConfiguration(cfg => cfg.AddProfile<MappingProfile>()).CreateMapper();
        }

        public async Task Consume(ConsumeContext<***> context)
        {
            await _bus.Publish(_mapper.Map<***>(context.Message));
        }

and is it correct way to create mapper here or it could be passed as well?


Solution

  • You don't need to inject IBus, and it's not the recommended approach for chaining messages. You should use context.Publish instead, which not only will publish your message, but also establish a link between those messages with a proper causation and conversation ids.

    In addition, injecting the service provider is a service locator antipattern. I could suggest reading at least the DI docs from Microsoft to understand how it should be done.

    If you configure your application following the documentation, you will get your dependencies injected when the consumer is instantiated. In particular, this example shows how it's done:

     services.AddMassTransit(x =>
     {
         x.AddConsumer<EventConsumer>();
         x.UsingRabbitMq((context, cfg) =>
         {
             cfg.ReceiveEndpoint("event-listener", e =>
             {
                 e.ConfigureConsumer<EventConsumer>(context);
             });
         });
     });
    

    When configured like this, the EventConsumer instance will get all its dependencies properly injected, if it has any, and these dependencies are properly registered in the services collection.

    But still, to publish a message from inside the consumer, you better use context.Publish.