Scenario:
- Web API application using multiple satellite library
- .NET Framework 4.6
- Simple Injector
- Rebus
- Rebus.AzureServiceBus
- Rebus.SimpleInjector
In my application there are multiple satellite library most of which have a class implementing SimpleInjector IPackage
interface, that is, to group container registrations in different libraries. Those packages get registered at Startup
container.RegisterPackages(AppDomain.CurrentDomain.GetAssemblies());
One of the packages contains Rebus configuration
IContainerAdapter adapter = new SimpleInjectorContainerAdapter( container );
Configure.With( adapter )
.Transport( t => t.UseAzureServiceBusAsOneWayClient( connectionString, AzureServiceBusMode.Standard ) )
.Routing( r =>
r.TypeBased()
.MapAssemblyOf<TransactionCreated>( "MyQueue" )
)
.Options( oc => {
oc.SetNumberOfWorkers( 1 );
} )
.Start();
This morning we have upgraded Rebus packages to the following versions:
- Rebus 4.0.1
- Rebus.AzureServiceBus 4.0.0
- Rebus.SimpleInjector 4.0.0
After the upgrade the system stopped working and now we get the following error
The container can't be changed after the first call to GetInstance, GetAllInstances and Verify. Please see https://simpleinjector.org/locked to understand why the container is locked. The following stack trace describes the location where the container was locked:
By debugging on the code we can see that another package get registered after the one that register rebus and so the reason of the error. We can confirm that no modification have been done at the code and it was correctly working as expected with the previous releases.
I can also confirm that by downgrading to these versions the problem disappear
- Rebus 3.1.5
- Rebus.AzureServiceBus 3.0.0
- Rebus.SimpleInjector 3.0.0
Any suggestion?
EDIT: As per @Steven request I am adding the full stack trace
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The container can't be changed after the first call to GetInstance, GetAllInstances and Verify. Please see https://simpleinjector.org/locked to understand why the container is locked. The following stack trace describes the location where the container was locked:
at Rebus.SimpleInjector.SimpleInjectorContainerAdapter.SetBus(IBus bus)
at Rebus.Config.RebusConfigurer.Start()
at XXX.YYY.EndpointEvents.Producer.IOC.EndpointEventsProducerModule.RegisterServices(Container container)
at SimpleInjector.PackageExtensions.RegisterPackages(Container container, IEnumerable assemblies)
at XXX.YYY.WebAPI.SimpleInjectorWebApiInitializer.InitializeContainer(Container container)
at XXX.YYY.WebAPI.SimpleInjectorWebApiInitializer.Initialize()
at XXX.YYY.WebAPI.Startup.Configuration(IAppBuilder app)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at Owin.Loader.DefaultLoader.<>c__DisplayClass12.<MakeDelegate>b__b(IAppBuilder builder)
at Owin.Loader.DefaultLoader.<>c__DisplayClass1<LoadImplementation>b__0(IAppBuilder builder)
at Microsoft.Owin.Host.SystemWeb.OwinHttpModule.<>c__DisplayClass2.<InitializeBlueprint>b__0(IAppBuilder builder)
at Microsoft.Owin.Host.SystemWeb.OwinAppContext.Initialize(Action startup)
at Microsoft.Owin.Host.SystemWeb.OwinBuilder.Build(Action startup)
at Microsoft.Owin.Host.SystemWeb.OwinHttpModule.InitializeBlueprint()
at System.Threading.LazyInitializer.EnsureInitializedCore[T](T& target, Boolean& initialized, Object& syncLock, Func valueFactory)
at Microsoft.Owin.Host.SystemWeb.OwinHttpModule.Init(HttpApplication context)
at System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers)
at System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context)
at System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context)
at System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext)
Sorry for being to late to react to this question :)
I finally had the time to understand how SimpleInjector wants container registrations to be made, and understand how the Rebus configuration API could somehow be bent into working that way.
It turned out that the usual
spell had to be moved somehow into a
Func<IBus>
, making it possible to finish ALL Rebus-relevant registrations (as well as your own) before actually starting the bus.The result (which is out in Rebus.SimpleInjector 5.0.0-b01 on NuGet.org just now) is this API:
which is how it can look if you are using SimpleInjector.Packaging, or simply
if all you have is a SimpleInjector
container
.When you think it is time to start the bus, you either
or you wait until
IBus
is resolved.