设置:使用SimpleInjector在asp.net mvc项目中重新开始。
我需要创建两个处理程序来接收来自特定队列的消息。按照我在SO answer上发现的内容,我创建了类似的代码。
在类库中,我有一个实现SimpleInjector IPackage
的类,其代码如下:
public void RegisterServices( Container container ) {
container.Register<IHandleMessages<MyMessage>, MyMessageHandler>( Lifestyle.Scoped );
IContainerAdapter adapter = new SimpleInjectorContainerAdapter( container );
Configure.With( adapter )
.Transport( t => t.UseAzureServiceBus( connectionString, "A_QUEUE_NAME", AzureServiceBusMode.Standard ) )
.Options( oc => {
oc.SetNumberOfWorkers( 1 );
oc.SimpleRetryStrategy( errorQueueAddress: "A_ERROR_QUEUE_NAME", maxDeliveryAttempts: 3 );
} )
.Start();
Configure.With(adapter
.Transport(t => t.UseAzureServiceBus(connectionString, "B_QUEUE_NAME")
.Options( oc => {
oc.SetNumberOfWorkers( 1 );
oc.SimpleRetryStrategy( errorQueueAddress: "B_ERROR_QUEUE_NAME", maxDeliveryAttempts: 3 );
} )
.Start();
}
然而,当调试器进入第二个Configure.With(...)调用时,我终止时出现错误说:
IBus类型已经注册。如果您打算解析IBus实现的集合,请使用RegisterCollection重载。更多信息:https://simpleinjector.org/coll1。如果您打算使用此新注册替换现有注册,则可以通过将Container.Options.AllowOverridingRegistrations设置为true来允许覆盖当前注册。更多信息:https://simpleinjector.org/ovrrd。
堆栈追踪:
[InvalidOperationException: Type IBus has already been registered. If your intention is to resolve a collection of IBus implementations, use the RegisterCollection overloads. More info: https://simpleinjector.org/coll1. If your intention is to replace the existing registration with this new registration, you can allow overriding the current registration by setting Container.Options.AllowOverridingRegistrations to true. More info: https://simpleinjector.org/ovrrd.]
SimpleInjector.Internals.NonGenericRegistrationEntry.ThrowWhenTypeAlreadyRegistered(InstanceProducer producer) +102
SimpleInjector.Internals.NonGenericRegistrationEntry.Add(InstanceProducer producer) +59
SimpleInjector.Container.AddInstanceProducer(InstanceProducer producer) +105
SimpleInjector.Container.AddRegistrationInternal(Type serviceType, Registration registration) +69
SimpleInjector.Container.AddRegistration(Type serviceType, Registration registration) +131
SimpleInjector.Container.RegisterSingleton(TService instance) +183
Rebus.SimpleInjector.SimpleInjectorContainerAdapter.SetBus(IBus bus) +55
Rebus.Config.RebusConfigurer.Start() +2356
MyModule.RegisterServices(Container container) +497
SimpleInjector.PackageExtensions.RegisterPackages(Container container, IEnumerable`1 assemblies) +50
Myproject.SimpleInjectorInitializer.InitializeContainer(Container container) +35
Myproject.SimpleInjectorInitializer.Initialize() +68
Myproject.Startup.Configuration(IAppBuilder app) +28
修改
然后我删除了第二个Configure.With( ... )
代码块,现在当我执行_bus.Send( message )
时,我在使用者流程中遇到另一个错误
处理ID为fef3acca-97f4-4495-b09d-96e6c9f66c4d的消息时未处理的异常1:SimpleInjector.ActivationException:没有注册类型IEnumerable&lt; IHandleMessages&lt; MyMessage&gt;&gt;可以找到。但是,有一个注册IHandleMessages&lt; MyMessage&gt ;;你的意思是调用GetInstance&lt; IHandleMessages&lt; MyMessage&gt;&gt;()或依赖于IHandleMessages&lt; MyMessage&gt;?或者您的意思是使用RegisterCollection注册类型集合?
堆栈追踪:
2017-04-13 10:21:03,805 [77] WARN Rebus.Retry.ErrorTracking.InMemErrorTracker -
at SimpleInjector.Container.ThrowMissingInstanceProducerException(Type serviceType)
at SimpleInjector.Container.GetInstanceForRootType[TService]()
at SimpleInjector.Container.GetInstance[TService]()
at SimpleInjector.Container.GetAllInstances[TService]()
at Rebus.SimpleInjector.SimpleInjectorContainerAdapter.<GetHandlers>d__3`1.MoveNext()
答案 0 :(得分:4)
我通常建议每个容器实例只保留一个IBus
,因为总线可以考虑&#34;应用程序&#34;就其本身而言,恰好与IoC容器是一个可以“托管”#34;申请一生的持续时间。
Rebus没有提供Conforming Container抽象,因为我同意Mark Seemann认为这是一个注定要失败的项目。实际上,正如the wiki page mentions一样,Rebus曾经提供过处理程序的自动注册,但结果证明是有问题的。
相反,Rebus鼓励您提供一个容器适配器&#34; (IContainerAdapter
)的实施,其职责是:
IBus
和IMessageContext
其中容器适配器是为Autofac,Castle Windsor,SimpleInjector等提供的。但是,不需要提供容器适配器 - Configure.With(...)
rant很高兴只接收一个&#34;处理程序活化剂&#34; (IHandlerActivator
的实现),所以如果您只想使用IoC容器查找处理程序并自己注册IBus
,那么您也可以通过实现IHandlerActivator
并查找你的容器中的处理程序。
TL; DR :Rebus方法是将IoC容器的实例视为单独的应用程序,因此只在其中注册一个IBus
是有意义的。
完全可以在一个进程中新建多个容器实例,以便托管多个应用程序(甚至是具有不同消息SLA的应用程序的多个实例)。
答案 1 :(得分:2)
例外情况:“类型IBus已经注册”。根据您的堆栈跟踪,第二次添加IBus是在SimpleInjectorContainerAdapter
内。你必须先找出它第一次注册的时间。这很容易做到;刚刚在创建IBus
之后注册了一个虚拟Container
作为第一次注册,并查看它在哪里爆炸的堆栈跟踪。
答案 2 :(得分:2)
你引用了我的答案(问题),所以我会与你分享我是如何实现它的。 正如您将看到的,使用特定接口,我将命令与事件分开。
然后,就在队列的消费部分,我做了这种注册:
public static void Register()
{
var assemblies = AppDomain.CurrentDomain.GetAssemblies()
.Where(i => i.FullName.StartsWith("MySolutionPrefix"))
;
var container = new Container();
// http://simpleinjector.readthedocs.io/en/latest/lifetimes.html#perexecutioncontextscope
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
var serviceType = typeof(IHandleMessages<>).Name;
// this is extension method to get specific handlers
IEnumerable<Type> commandHandlers = assemblies.GetHandlers(serviceType, typeof(ICommand));
container.Register(typeof(IHandleMessages<>), commandHandlers.Concat(new List<Type> { typeof(HistorizeCommandHanlder) }));
// NOTE Just command Handlers
container.RegisterCollection(typeof(IHandleMessages<>), commandHandlers);
var bus = Configure.With(new SimpleInjectorContainerAdapter(container))
//.... logging, transport (I created my own transport on mongoDb), routing, sagas and so on
.Options(o =>
{
// This simply my personal transport as Register<IOneWayClientTransport>
o.ConfigureDecouplingDatabase(db, settings.TopicBasedMessageQueueName);
// this is more complicated because i want that automatically the message is copied on
// a separate topic for each handler
o.EnableHandlerDecoupling(settings.DecouplingHandlersRegistration);
})
.Start();
container.Verify();
// It is necessary because otherwise it sends published messages to no-one
commandHandlers.GetHandledSubTypes(serviceType, typeof(IVersionedEvent))
.ToList()
.ForEach(i => bus.Subscribe(i).Wait());
// NOTE just events handlers
IEnumerable<Type> eventHandlers = assemblies
.GetHandlers(serviceType, typeof(IVersionedEvent))
.Except(commandHandlers)
//.Except(new List<Type> { typeof(TempHandlerLogDecorator) })
;
foreach (var handler in eventHandlers)
ConfigureServiceBus(mongoDbConnectionProvider, db, handler.FullName, new[] { handler });
}
private static IBus ConfigureServiceBus(MongoDbConnectionProvider mongoDbConnectionProvider, IMongoDatabase db, string inputQueueName, IEnumerable<Type> handlers)
{
var container = new Container();
container.Options.DefaultScopedLifestyle = new ExecutionContextScopeLifestyle();
container.RegisterCollection(typeof(IHandleMessages<>), handlers);
var bus = Configure.With(new SimpleInjectorContainerAdapter(container))
.... logging, Subscriptions
// this is a consumer only for inputQueueName
.Transport(t => t.UseMongoDb(db, settings.TopicBasedMessageQueueName, inputQueueName))
.Options(o =>
{
o.ConfigureDecouplingDatabase(db, settings.TopicBasedMessageQueueName);
o.EnableHandlerDecoupling(settings.DecouplingHandlersRegistration);
})
.Start();
container.Verify();
handlers.GetHandledSubTypes(typeof(IHandleMessages<>).Name, typeof(IVersionedEvent))
.ToList()
.ForEach(i => bus.Advanced.Topics.Subscribe(i.GetDecoupledTopic(settings.DecouplingHandlersRegistration)).Wait());
return bus;
}
我仍在使用Rebus 3.0.1和SimpleInjector 3.2.3。