messagingspring.netservicebusrhino-servicebus

Get exception when Rhino ServiceBus is starting


I have my system divided into 2 parts. Both parts communicate with each other using Rhino Service Bus. There is no problem on Windows 7, but if I start it anywhere else (WinXP, Server 2003, ... ) I get the following exception when I call 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)

Here is fragment form 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

Solution

  • Problem solved: In the MSMQ version 3 or lower (on systems like Windows XP, Windows Server 2003), subqueues are not supported and therefore Rhino SB uses FlatQueueStrategy for manageing the queues. Problems occurs when Spring object container is configured. Concretely there are two places in the class Rhino.ServiceBus.Spring.SpringBuilder where modifications need to be done.

    1) method 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);
    }
    

    the second part of if statement is always called, because FlatQueueStrategy doesn't have constructor with parameters of type IQueueStrategy and Uri. But it doesn't even have the constructor without parametrs. So FlatQueueStrategy is not registered correctly in the object container. The modification for this part would be:

    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) method RegisterDefaultServices

    Next problem is in the method 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());
    

    the method RegisterMsmqTransport is called before IEndpointRouter is registered in object container. IEndpointRouter is used in the method RegisterMsmqTransport (see 1) and therefore method call

        applicationContext.Get<IEndpointRouter>()
    

    produces an exception. The modification here would be:

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