question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Problem with integration of MassTransit.SimpleInjector in ASP.NET Core 3.0

See original GitHub issue

Is this a bug report?

Probably. ‘The registered delegate for type ConsumeContext returned null.’ exception will occur during asp.net core 3.0 application starting. This application uses the latest MassTransit.RabbitMq and MassTransit.SimpleInjector NuGet packages.

Can you also reproduce the problem with the latest version?

This problem reproduced on latest version of:

  1. MassTransit.SimpleInjector 5.5.6
  2. MassTransit.RabbitMQ 5.5.6
  3. SimpleInjector.Integration.AspNetCore 4.7.1
  4. SimpleInjector.Integration.AspNetCore.Mvc.Core 4.7.1
  5. ASP.NET Core 3.0

Environment

  1. Operating system: Windows 10(1903), Docker 2.1.0.4(39773), Alpine 3.9
  2. Visual Studio version: 2019
  3. Dotnet version: .Net Core 3.0

Steps to Reproduce

I have created one simple asp.net core application. It acts as a consumer and it acts as producer (for simplify).

  1. Install Docker Desktop (download) (with linux containers)
  2. Checkout project with a reproducible example on your local pc. git clone https://github.com/iVova/AspNetCore3_MassTransit_SimpleInjector.git
  3. Just run the project in Visual Studio

Expected Behavior

  1. The web application should run without any exception and an open browser with the default URL.
  2. SendNotificationOnUserCreatedConsumer consumer should instantiate with IClock application service and receive a message

Actual Behavior

During the starting, web application exception occurred on container verification. (as recommended SimpleInjector)

Exception message:

The configuration is invalid. Creating the instance for type ISendEndpointProvider failed. The registered delegate for type ISendEndpointProvider threw an exception. The registered delegate for type ConsumeContext threw an exception. The registered delegate for type ConsumeContext returned null.

See attached screenshot. MassTransit-SimpleInjector_ConsumerContext_error

Reproducible Demo project

On GitHub: https://github.com/iVova/AspNetCore3_MassTransit_SimpleInjector

Reproducible Demo code

StartUp.cs
using MassTransit;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using MyAspCoreApp.Consumers;
using MyAspCoreApp.Services;
using SimpleInjector;
using SimpleInjector.Lifestyles;
using System;

namespace MyAspCoreApp
{
    public class Startup
    {
        private readonly Container _container = new Container();

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            _container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();

            services.AddControllers();

            services.AddSimpleInjector(_container, options =>
            {
                // AddAspNetCore() wraps web requests in a Simple Injector scope.
                options.AddAspNetCore()
                    .AddControllerActivation();
            });

            // !!!
            AddMassTransitThroughSimpleInjector(services, _container);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // !!!!
            ConfigureSimpleInjector(app, _container);

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }

        public static IApplicationBuilder ConfigureSimpleInjector(IApplicationBuilder app, Container container)
        {
            // UseSimpleInjector() enables framework services to be injected into
            // application components, resolved by Simple Injector.
            app.UseSimpleInjector(container, options =>
            {
                // Add custom Simple Injector-created middleware to the ASP.NET pipeline.
                // options.UseMiddleware<CustomMiddleware1>(app);

                // Optionally, allow application components to depend on the
                // non-generic Microsoft.Extensions.Logging.ILogger abstraction.
                options.UseLogging();
            });

            InitializeContainer(container);

            // Always verify the container
            container.Verify();

            var busControl = container.GetInstance<IBusControl>();
            busControl.Start();

            return app;
        }

        private static void InitializeContainer(Container container)
        {
            // Add application services. For instance:
            container.Register<IClock, SystemClock>(Lifestyle.Scoped);
        }

        public static void AddMassTransitThroughSimpleInjector(IServiceCollection services, Container container)
        {
            container.AddMassTransit(configurator =>
            {
                configurator.AddConsumersFromNamespaceContaining<SendNotificationOnUserCreatedConsumer>();

                configurator.AddBus(() =>
                {
                    var bus = Bus.Factory.CreateUsingRabbitMq(cfg =>
                    {
                        var host = cfg.Host(new Uri("rabbitmq://myaspcoreapp.rabbitMq"), hostConfigurator =>
                        {
                            hostConfigurator.Username("guest");
                            hostConfigurator.Password("guest");
                        });

                        cfg.ConfigureEndpoints(container);
                    });

                    return bus;
                });
            });
        }
    }
}
Producer
using MassTransit;
using Microsoft.AspNetCore.Mvc;
using MyAspCoreApp.Messages;
using System;
using System.Threading.Tasks;

namespace MyAspCoreApp.Controllers
{
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController : ControllerBase
    {
        private readonly IBus _bus;

        public WeatherForecastController(IBus bus)
        {
            _bus = bus;
        }

        [HttpGet]
        public async Task Get()
        {
            var message = new UserCreatedMessage
            {
                UserId = Guid.NewGuid()
            };

            await _bus.Publish(message);
        }
    }
}
Consumer
using MassTransit;
using MyAspCoreApp.Messages;
using MyAspCoreApp.Services;
using System.Threading.Tasks;

namespace MyAspCoreApp.Consumers
{
    public class SendNotificationOnUserCreatedConsumer : IConsumer<UserCreatedMessage>
    {
        private readonly IClock _clock;

        public SendNotificationOnUserCreatedConsumer(IClock clock)
        {
            _clock = clock;
        }

        public Task Consume(ConsumeContext<UserCreatedMessage> context)
        {
            var time = _clock.UtcNow;
            return Task.CompletedTask;
        }
    }
}

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:5
  • Comments:19 (7 by maintainers)

github_iconTop GitHub Comments

3reactions
enricoribellicommented, Feb 3, 2020

Could you please say when can we expect the latest release containing this fix by any chance?

2reactions
dotnetjunkiecommented, Jan 27, 2020

So, this is only an issue because the container validation isn’t creating the scope. MassTransit creates the scope and this error never happens in reality. It’s only in the validation, where there is no scope.

Note that this could be a problem for other DI Containers as well as there are other containers that have this verification feature. Libraries that come to mind are StructureMap, Lamar, but even Microsoft.Extensions.DependencyInjection 3.0 contains this feature. This means that you should be very careful in the registration of these stateful objects to be injected directly.

That change still doesn’t deal with the fact that validate calls without a scope, so the ConsumeContext registration fails

I’m not sure what this means. When you call SimpleInjector.Container.Verify(), Simple Injector will iterate through the registrations and resolve every one of them, and it will do so within the context of a SimpleInjector.Scope that is created and disposed for that occasion.

But if everything else fails, you can change the registration of ConsumeContext to take verification into consideration:

container.Register(
    () => container.GetInstance<ScopedConsumeContextProvider>().GetContext() ?? (
        container.IsVerifying
            ? new ConsumeContext()
            : throw new Exception("Some error")),
    Lifestyle.Scoped);

This returns a dummy ConsumeContext in case the container is currently verifying the graph. Do note, however, that other DI Containers might not consist of such a IsVerifying property (MS.DI certainly doesn’t).

Read more comments on GitHub >

github_iconTop Results From Across the Web

MassTransit and .NET Core DI - how to resolve ...
Mass Transit requires parameterless constructor for consumers. I need to use e.g. logger, dbContext etc in my consumers and I would like to...
Read more >
MassTransit.Redis 8.1.0
MassTransit. MassTransit provides a developer-focused, modern platform for creating distributed applications without complexity.
Read more >
Using Simple Injector
Using Simple Injector¶. This section will walk you through the basics of Simple Injector. After reading this section, you will have a good...
Read more >
MassTransit.SimpleInjector
MassTransit SimpleInjector container support; MassTransit is a message-based distributed application framework for .NET http://masstransit-project.com/
Read more >
What are some nuget packages that you use often or find ...
ASP.NET Core was heavily reliant on Newtonsoft.Json pre 3.0. ... Integrate with MVC, there's a NuGet for that. Graylog sink? Yup!
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found