Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 973
Marek Urbanowicz Avatar asked Dec 23 '17 16:12

Marek Urbanowicz


1 Answers

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.

like image 86
poke Avatar answered Sep 18 '22 15:09

poke