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.
This problem reproduced on latest version of:
I have created one simple asp.net core application. It acts as a consumer and it acts as producer (for simplify).
git clone https://github.com/iVova/AspNetCore3_MassTransit_SimpleInjector.gitSendNotificationOnUserCreatedConsumer consumer should instantiate with IClock application service and receive a messageDuring the starting, web application exception occurred on container verification. (as recommended SimpleInjector)
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.

On GitHub: https://github.com/iVova/AspNetCore3_MassTransit_SimpleInjector
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;
});
});
}
}
}
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);
}
}
}
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;
}
}
}
Is there a workaround for this issue?
Does it work if you don't call Verify on the container?
The application will start without any errors and the message will send if we remove a Verify method and register IClock service as a Scoped lifestyle.
I am not sure to remove a Verify method This method very helpful during developing.
So why isn't IClock registered as scoped? If you register it as Scoped, does your Verify method work?
No. Verify method does not work even with Scoped IClock. (I tried. Same error.)
Maybe it is related to this simple injecto's issue: https://github.com/simpleinjector/SimpleInjector/issues/754
I'm closing this, I doubt it's MassTransit.
The problem must be resolved on SimpleInjector 4.8+
Same error.
Even after upgrade application to the latest version of ASP.Net Core 3.1, SimpleInjector 4.8.1 and MassTransit 6.0.0
There is a branch with the latest changes Asp.Core3.1_SimpleInjector4.8.1_MassTransit6.0
Exception:
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.
Can anyone post a full stack trace of the exception?
Full StackTrace:
System.InvalidOperationException: 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.
---> SimpleInjector.ActivationException: 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.
---> SimpleInjector.ActivationException: The registered delegate for type ConsumeContext threw an exception. The registered delegate for type ConsumeContext returned null.
---> SimpleInjector.ActivationException: The registered delegate for type ConsumeContext returned null.
at SimpleInjector.Registration.ThrowWhenNullTService
at SimpleInjector.Scope.CreateAndCacheInstanceTImplementation
at SimpleInjector.Scope.GetInstanceInternalTImplementation
at SimpleInjector.Advanced.Internal.LazyScopedRegistration1.GetInstance(Scope scope)
at lambda_method(Closure )
at SimpleInjector.InstanceProducer.BuildAndReplaceInstanceCreatorAndCreateFirstInstance()
at SimpleInjector.InstanceProducer.GetInstance()
--- End of inner exception stack trace ---
at SimpleInjector.InstanceProducer.GetInstance()
at SimpleInjector.Container.System.IServiceProvider.GetService(Type serviceType)
at MassTransit.SimpleInjectorIntegration.ContainerResolutionExtensions.TryGetInstance[T](Container container)
at MassTransit.SimpleInjectorIntegration.ContainerResolutionExtensions.GetConsumeContext(Container container)
at MassTransit.SimpleInjectorIntegration.Registration.SimpleInjectorRegistrationConfigurator.GetSendEndpointProvider()
at lambda_method(Closure )
at SimpleInjector.Lifestyles.SingletonLifestyle.SingletonLifestyleRegistration1.CreateInstance(Func1 instanceCreator)
at SimpleInjector.Lifestyles.SingletonLifestyle.SingletonLifestyleRegistration1.CreateInstanceWithNullCheck()
at SimpleInjector.Lifestyles.SingletonLifestyle.SingletonLifestyleRegistration1.GetInterceptedInstance()
at SimpleInjector.Lifestyles.SingletonLifestyle.SingletonLifestyleRegistration1.BuildExpression()
at SimpleInjector.Lifestyles.HybridRegistration.BuildExpression()
at SimpleInjector.InstanceProducer.BuildExpressionInternal()
at SimpleInjector.Internals.LazyEx`1.get_Value()
at SimpleInjector.InstanceProducer.BuildExpression()
--- End of inner exception stack trace ---
at SimpleInjector.InstanceProducer.BuildExpression()
at SimpleInjector.InstanceProducer.VerifyExpressionBuilding()
--- End of inner exception stack trace ---
at SimpleInjector.InstanceProducer.VerifyExpressionBuilding()
at SimpleInjector.Container.VerifyThatAllExpressionsCanBeBuilt(InstanceProducer[] producersToVerify)
at SimpleInjector.Container.VerifyThatAllExpressionsCanBeBuilt()
at SimpleInjector.Container.VerifyInternal(Boolean suppressLifestyleMismatchVerification)
at SimpleInjector.Container.Verify(VerificationOption option)
at SimpleInjector.Container.Verify()
at MyAspCoreApp.Startup.ConfigureSimpleInjector(IApplicationBuilder app, Container container) in D:dev\git\AspNetCore3_MassTransit_SimpleInjector\MyAspCoreApp\Startup.cs:line 85
at MyAspCoreApp.Startup.Configure(IApplicationBuilder app, IWebHostEnvironment env) in D:dev\git\AspNetCore3_MassTransit_SimpleInjector\MyAspCoreApp\Startup.cs:line 53
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.Invoke(Object instance, IApplicationBuilder builder)
at Microsoft.AspNetCore.Hosting.ConfigureBuilder.<>c__DisplayClass4_0.
at Microsoft.AspNetCore.Hosting.GenericWebHostBuilder.<>c__DisplayClass13_0.
at SimpleInjector.Integration.AspNetCore.RequestScopingStartupFilter.<>c__DisplayClass2_0.
at Microsoft.AspNetCore.Mvc.Filters.MiddlewareFilterBuilderStartupFilter.<>c__DisplayClass0_0.
at Microsoft.AspNetCore.HostFilteringStartupFilter.<>c__DisplayClass0_0.
at Microsoft.AspNetCore.Hosting.GenericWebHostService.StartAsync(CancellationToken cancellationToken)
The problem likely lies in this part of the integration library:
Apparently, the ScopedConsumeContextProvider.GetContext() is allowed to return null. Simple Injector, however, forbids registered delegates (such as the ) => container.GetInstance<ScopedConsumeContextProvider>().GetContext() for return null.
The integration library, tries to conditionally load the ConsumeContext here:
By making use of Simple Injector's IServiceProvider.GetService(Type) method:
But the assumption here is that GetService(Type) returns null in case there exists a registration, which returns null from its delegate. This assumption, unfortunately, is wrong. GetService(Type) only returns null when there exists no registration. In case there is a registration, as there is in this case, the registration cannot return null.
Because of this, I would suggest removing the registration for ConsumeContext and changing the ContainerResolutionExtensions.GetConsumeContext method to the following:
``` c#
public static ConsumeContext GetConsumeContext(this Container container) =>
Lifestyle.Scoped.GetCurrentScope(container) != null
? container.GetInstance
: null;
Or perhaps even simply (depending on whether or not it is even valid to have no active `Scope`):
``` c#
public static ConsumeContext GetConsumeContext(this Container container) =>
container.GetInstance<ScopedConsumeContextProvider>().GetContext();
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.
I'll look at adding the code you suggested to the GetConsumeContext method, assuming that the current scope is tracked through an async lifecycle, and you can check if the container validation passes at that point without crashing.
That change still doesn't deal with the fact that validate calls without a scope, so the ConsumeContext registration fails. I'm adding a MissingConsumeContext that throws an exception on every method which will be returned if no scope is present, so that validation passes.
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:
c#
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).
I'll recheck the other containers. I did add this same behavior to Windsor and MS DI at the time of fixing this one, I'll verify that I've done the same for others. In some cases, it isn't needed since the container has the ability to add registrations when the scope is created (which is done with Autofac, Lamar, StructureMap 鈥撀爏o they aren't a concern).
Is being able to injecting ConsumeContext into components a hard requirement?
It isn't just ConsumeContext, it's IPublishEndpoint and ISendEndpointProvider so that dependent components used by a consumer that may need to send commands or publish events are able to do so within the context of the consumer. It's the entire reason for the ScopedContextProvider's existence.
Could you please say when can we expect the latest release containing this fix by any chance?
Most helpful comment
Could you please say when can we expect the latest release containing this fix by any chance?