Problem with integration of MassTransit.SimpleInjector in ASP.NET Core 3.0
See original GitHub issueIs 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:
- MassTransit.SimpleInjector 5.5.6
- MassTransit.RabbitMQ 5.5.6
- SimpleInjector.Integration.AspNetCore 4.7.1
- SimpleInjector.Integration.AspNetCore.Mvc.Core 4.7.1
- ASP.NET Core 3.0
Environment
- Operating system: Windows 10(1903), Docker 2.1.0.4(39773), Alpine 3.9
- Visual Studio version: 2019
- 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).
- Install Docker Desktop (download) (with linux containers)
- Checkout project with a reproducible example on your local pc.
git clone https://github.com/iVova/AspNetCore3_MassTransit_SimpleInjector.git
- Just run the project in Visual Studio
Expected Behavior
- The web application should run without any exception and an open browser with the default URL.
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.
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:
- Created 4 years ago
- Reactions:5
- Comments:19 (7 by maintainers)
Could you please say when can we expect the latest release containing this fix by any chance?
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.
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 aSimpleInjector.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: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 aIsVerifying
property (MS.DI certainly doesn’t).