Obtenha uma exceção quando o Rhino ServiceBus estiver iniciando
-
28-10-2019 - |
Pergunta
Eu tenho meu sistema dividido em 2 partes.Ambas as partes se comunicam com cada
outro usando Rhino Service Bus.
Não há problema no Windows 7, mas se eu iniciá-lo em qualquer outro lugar
(WinXP, Server 2003, ...) Recebo a seguinte exceção
quando eu chamo Rhino.ServiceBus.Hosting.DefaultHost.Start(..)
:
System.NullReferenceException: Object reference not set to an instance of an object.
at Spring.Objects.Factory.Support.AbstractObjectFactory.GetObjectFromFactoryObject(IFactoryObject factory, String objectName, RootObjectDefinition rod)
at Spring.Objects.Factory.Support.AbstractObjectFactory.GetObjectForInstance(Object instance, String name, String canonicalName, RootObjectDefinition rod)
at Spring.Objects.Factory.Support.AbstractObjectFactory.GetObjectInternal(String name, Type requiredType, Object[] arguments, Boolean suppressConfigure)
at Spring.Objects.Factory.Support.AbstractObjectFactory.GetObject(String name)
at Spring.Context.Support.AbstractApplicationContext.GetObject(String name)
at Rhino.ServiceBus.Spring.ApplicationContextExtensions.Get(IApplicationContext context, Type type)
at Rhino.ServiceBus.Spring.ApplicationContextExtensions.Get[T](IConfigurableApplicationContext context)
at Rhino.ServiceBus.Spring.SpringBootStrapper.GetInstance[T]()
at Rhino.ServiceBus.Hosting.DefaultHost.InitailizeBus(String asmName)
at Rhino.ServiceBus.Hosting.DefaultHost.Start(String asmName)
Aqui está o fragmento do Spring log:
2012-01-14 13:25:01,084 DEBUG Spring.Objects.Factory.Support.DefaultListableObjectFactory - Invoking IObjectPostProcessors after initialization of object '351a5f07-e33d-4be0-84cf-1738a8feba24'
2012-01-14 13:25:01,084 DEBUG Spring.Objects.Factory.Support.DefaultListableObjectFactory - GetObjectInternal: returning instance for objectname 351a5f07-e33d-4be0-84cf-1738a8feba24
2012-01-14 13:25:01,084 ERROR Spring.Objects.Factory.Support.DefaultListableObjectFactory - GetObjectInternal: error obtaining object Rhino.ServiceBus.Msmq.FlatQueueStrategy
2012-01-14 13:25:01,084 ERROR Spring.Objects.Factory.Support.DefaultListableObjectFactory - GetObjectInternal: error obtaining object Rhino.ServiceBus.Msmq.MsmqTransport
2012-01-14 13:25:01,084 ERROR Spring.Objects.Factory.Support.DefaultListableObjectFactory - GetObjectInternal: error obtaining object 1a769f24-5410-4cee-8d7a-76c3a91b1ce1
Solução
Problema resolvido: No MSMQ versão 3 ou inferior (em sistemas como Windows XP, Windows Server 2003), as subfilas não são suportadas e, portanto, Rhino SB usa FlatQueueStrategy para gerenciar as filas. Ocorrem problemas quando o contêiner de objeto Spring é configurado. Concretamente, existem dois lugares na classe Rhino.ServiceBus.Spring.SpringBuilder onde as modificações precisam ser feitas.
1) método RegisterMsmqTransport :
if (queueStrategyType.GetConstructor(new[] { typeof(IQueueStrategy), typeof(Uri) }) != null)
{
applicationContext.RegisterSingleton(queueStrategyType, typeof (IQueueStrategy).FullName, applicationContext.Get<IEndpointRouter>(), config.Endpoint);
}
else
{
// use default
applicationContext.RegisterSingleton(queueStrategyType);
}
a segunda parte da instrução if é sempre chamada, porque FlatQueueStrategy não tem construtor com parâmetros do tipo IQueueStrategy e Uri. Mas não tem nem o construtor sem parâmetros. Portanto, FlatQueueStrategy não está registrado corretamente no contêiner de objetos. A modificação para esta parte seria:
if (queueStrategyType.GetConstructor(new[] { typeof(IEndpointRouter), typeof(Uri) }) != null)
{
applicationContext.RegisterSingleton(queueStrategyType, typeof (IQueueStrategy).FullName, applicationContext.Get<IEndpointRouter>(), config.Endpoint);
}
else
{
// use default
applicationContext.RegisterSingleton(queueStrategyType);
}
2) método RegisterDefaultServices
O próximo problema está no método RegisterDefaultServices:
applicationContext.RegisterSingleton<IServiceLocator>(() => new SpringServiceLocator(applicationContext));
applicationContext.RegisterSingletons<IBusConfigurationAware>(typeof(IServiceBus).Assembly);
foreach (var busConfigurationAware in applicationContext.GetAll<IBusConfigurationAware>())
{
busConfigurationAware.Configure(config, this); // here is the method RegisterMsmqTransport called
}
foreach (var module in config.MessageModules)
{
applicationContext.RegisterSingleton(module, module.FullName);
}
applicationContext.RegisterSingleton<IReflection>(() => new DefaultReflection());
applicationContext.RegisterSingleton(config.SerializerType);
applicationContext.RegisterSingleton<IEndpointRouter>(() => new EndpointRouter());
o método RegisterMsmqTransport é chamado antes de IEndpointRouter ser registrado no contêiner de objeto. IEndpointRouter é usado no método RegisterMsmqTransport (ver 1) e, portanto, chamada de método
applicationContext.Get<IEndpointRouter>()
produz uma exceção. A modificação aqui seria:
applicationContext.RegisterSingleton<IServiceLocator>(() => new SpringServiceLocator(applicationContext));
applicationContext.RegisterSingletons<IBusConfigurationAware>(typeof(IServiceBus).Assembly);
applicationContext.RegisterSingleton<IReflection>(() => new DefaultReflection());
applicationContext.RegisterSingleton<IEndpointRouter>(() => new EndpointRouter());
foreach (var busConfigurationAware in applicationContext.GetAll<IBusConfigurationAware>())
{
busConfigurationAware.Configure(config, this);
}
foreach (var module in config.MessageModules)
{
applicationContext.RegisterSingleton(module, module.FullName);
}
applicationContext.RegisterSingleton(config.SerializerType);