Marek Urbanowicz
Marek Urbanowicz

Reputation: 13644

MassTransit and .NET Core DI - how to resolve dependencies with parameterless constructor?

I am working on the app using .NET Core 2 and MassTransit 4(dev).

Mass Transit requires parameterless constructor for consumers. I need to use e.g. logger, dbContext etc in my consumers and I would like to keep using native DI from .NET Core so I would prefer not to have to add Autofac etc (if possible?). It is causing the issue when .NET Core DI cannot inject my deps because my consumer is created with parameterless constructor...

Is there any way to resolve dependencies using native net core DI while having parameterless constructor OR is there some way of declaring endpoints of MassTransit which would allow to do that other than standard:

sbc.ReceiveEndpoint(host, Configuration["QueueName"], 
                    e => { e.Consumer<MyAwesomeConsumer>();});

I have tried:

// =========== MASS TRANSIT ===============
            var serviceProvider = services.BuildServiceProvider();
            services.AddSingleton<MyAwesomeConsumer, MyAwesomeConsumer>();
            var bus = Bus.Factory.CreateUsingRabbitMq(sbc =>
            {
                var host = sbc.Host(new Uri("rabbitmq://localhost"), h =>
                {
                    h.Username("guest");
                    h.Password("guest");
                });

                sbc.ReceiveEndpoint(host, Configuration["QueueName"],
                    e =>
                    {
                        e.Consumer(typeof(MyAwesomeConsumer), serviceProvider.GetService);
                    });
            });

Application lifts up but as soon as first message arrives I am getting an error: MassTransit.ConsumerException: Unable to resolve consumer type 'AuthService.Integrations.MyAwesomeConsumer'.

I will appreciate any help. I hope it's clear what I am asking about.

Upvotes: 19

Views: 32053

Answers (2)

Lloyd Powell
Lloyd Powell

Reputation: 18780

I also had the same issue and poke's answer didn't work for me as I needed to use DI for IBus, IPublishEndpoint and ISendEndpointProvider.

I found this example here

services.AddSingleton(provider => Bus.Factory.CreateUsingRabbitMq(cfg =>
{
   var host = cfg.Host("localhost", "/", h => { });

   cfg.ReceiveEndpoint(host, "web-service-endpoint", e =>
   {
      e.Consumer<DoSomethingConsumer>(provider);
   });
}));

Upvotes: 10

poke
poke

Reputation: 387647

If you are using the Microsoft.Extensions.DependencyInjection container (which is the default with ASP.NET Core), then you will need the MassTransit.Extensions.DependencyInjection package for MassTransit. Note that the package is currently only available as a pre-release version and also requires a pre-release version of MassTransit. Furthermore, the new package is part of a massive migration for .NET Standard, which still isn’t complete, so you should probably be a bit careful as there are likely going to be quite a few moving parts until the final release.

Since the package isn’t officially released, there also isn’t any documentation on it yet. But from looking at the pull request that introduced it and the current source, I think what you need to do is the following:

In Startup.ConfigureServices, you need to add MassTransit, just like you would add other services:

services.AddMassTransit(c =>
{
    c.AddConsumer<MyConsumer>();
    c.AddConsumer<MyOtherConsumer>();

    // or sagas
    c.AddSaga<MySaga>();
});

// you still need to register the consumers/sagas
services.AddScoped<MyConsumer>();
services.AddScoped<MyOtherConsumer>();
services.AddSingleton<ISagaRepository<MySaga>, InMemorySagaRepository<MySaga>>();

In the configure action, you need to register you consumers and sagas in order for MassTransit to resolve them properly later.

Then, in your bus configuration, you would call LoadFrom with the service provider:

sbc.ReceiveEndpoint(host, Configuration["QueueName"], e =>
{
    e.LoadFrom(serviceProvider);
});

As for where you should do this (also in order to have access to the service provider), I would suggest you to do it in your Startup’s Configure method. The method can take any dependency as an argument, so you can easily inject the service provider there:

public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider, IApplicationLifetime applicationLifetime)
{
    var bus = Bus.Factory.CreateUsingRabbitMq(sbc =>
    {
        var host = sbc.Host(new Uri("rabbitmq://localhost"), h =>
        {
            h.Username("guest");
            h.Password("guest");
        });

        sbc.ReceiveEndpoint(host, Configuration["QueueName"], e =>
        {
            e.LoadFrom(serviceProvider);
        });
    });

    // start/stop the bus with the web application
    applicationLifetime.ApplicationStarted.Register(bus.Start);
    applicationLifetime.ApplicationStopped.Register(bus.Stop);
}

One final disclaimer though: I personally haven’t used MassTransit, so I don’t really know if this makes actual sense for the library.

Upvotes: 21

Related Questions