Rebus with Simple Injector 重大变更

Rebus with Simple Injector breaking change

场景:

在我的应用程序中有多个卫星库,其中大部分都有一个 class 实现 SimpleInjector IPackage 接口,即,将容器注册分组在不同的库中。这些包在 Startup

注册
container.RegisterPackages(AppDomain.CurrentDomain.GetAssemblies());

其中一个包包含 Rebus 配置

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();

今天早上我们已经将 Rebus 软件包升级到以下版本:

升级后系统停止工作,现在我们得到以下错误

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:

通过调试代码可以看出在注册rebus之后又注册了一个包,所以报错的原因。我们可以确认没有对代码进行任何修改,并且它在以前的版本中按预期正常工作。

我还可以确认,通过降级到这些版本,问题就会消失

有什么建议吗?

编辑:根据@Steven 的要求,我添加了完整的堆栈跟踪

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)

您的 EndpointEventsProducerModule 正在呼叫 RebusConfigurer.Start。开始从容器解析 IBus

由于模块可以按任何顺序调用,因此您应该只在模块中进行注册。删除 Start 调用并在调用 container.Verify() 后调用它。

如您所见here添加了新代码以确保总线已处理,这引入了一个问题,您的代码似乎没问题,只需要等待修复。新线下方

 +            // cheat and activate the IBus singleton behind the scenes, thus ensuring that the container will dispose it when it is time
 +            var registration = _container.GetRegistration(typeof(IBus));
 +  +            registration.GetInstance();
 +

抱歉来晚了回答这个问题:)

我终于有时间了解 SimpleInjector 如何进行容器注册,并了解 Rebus 配置 API 如何以某种方式弯曲成那样工作。

原来是平时的

Configure.With(new MyFavoriteContainerAdapter(container))
    .(...)
    .Start();

咒语必须以某种方式移动到 Func<IBus> 中,这样就可以在实际启动总线之前完成所有与 Rebus 相关的注册(以及您自己的注册)。

结果(刚刚在 NuGet.org 上的 Rebus.SimpleInjector 5.0.0-b01 中出现)是这样的 API:

public class RebusPackage : IPackage
{
    public void RegisterServices(Container container)
    {
        Console.WriteLine("Calling RebusPackage");

        container.ConfigureRebus(
            configurer => configurer
                .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "test"))
                .Start()
        );

    }
}

如果您使用 SimpleInjector.Packaging 或简单地使用

,它会是这样的
container.ConfigureRebus(
    configurer => configurer
        .Transport(t => t.UseInMemoryTransport(new InMemNetwork(), "test"))
        .Start()
);

如果你只有一个 SimpleInjector container

当您认为是时候启动公交车时,您可以

container.StartBus();

或者你等到 IBus 解决。