11

I am using Unity App Block as my IOC container for my service layer of a WCF project. This works quite well using the Unity.WCF library to plug it into each WCF service.

I recently introduced RabbitMQ into my service layer and I am currently using the "using" blocks to connect and add to the queue. I dont like this though and am looking to use the HierachicalLifetimeManager to create and destroy my connection to RabbitMQ as I need them? Does this sound correct?

I'm looking for a sample of this, or atleast some guidance on the best approach? (e.g. Should I encapsulate the connection and inject into each service as needed? How would I encapsulate RabbitMQ consumer etc?)

Lukazoid
  • 19,016
  • 3
  • 62
  • 85
Neil Hosey
  • 465
  • 6
  • 23

2 Answers2

6

I would advise registering the IConnection as a singleton.

To register the IConnection as a singleton in Unity you would use a ContainerControlledLifetimeManager, e.g.

var connectionFactory = new ConnectionFactory
{
    // Configure the connection factory
};
unityContainer.RegisterInstance(connectionFactory);

unityContainer.RegisterType<IConnection, AutorecoveringConnection>(new ContainerControlledLifetimeManager(),
    new InjectionMethod("init"));

The AutorecoveringConnection instance, once resolved for the first time will stay alive until the owning UnityContainer is disposed.

Because we have registered the ConnectionFactory with Unity, this will automatically be injected into the constructor of AutorecoveringConnection. The InjectionMethod ensures that the first time the AutorecoveringConnection is resolved, the init method is invoked.

As for your question about whether you should abstract away RabbitMQ from your services, my answer would be yes, however I would not simply create an IMessageQueue abstraction. Think about what purpose you are using your message queue for, is it to push statuses? If so, have an IStatusNotifier interface with a concrete implementation for RabbitMQ. If it's to fetch updates, have an IUpdateSource interface with a concrete implementation for RabbitMQ. You can see where I am going with this.

If you create an abstraction for a Message Queue, you are limiting yourself to features only available across all Message Queue implementations. By having a different implementation of IStatusNotifier for different Message Queue implementations, you are able to take advantage of features which are unique to different technologies while also remaining flexible in case completely different technologies are employed in future (e.g. Writing to a SQL database or outputting to a console).

Lukazoid
  • 19,016
  • 3
  • 62
  • 85
1

With RabbitMQ you want your IConnection to be re-used all the time, you don't want it in a "using" block. Here is my IOC binding using Ninject, note the InSingletonScope, this is what you want.

    Bind<IConnection>()
        .ToMethod(ctx =>
                  {
                      var factory = new ConnectionFactory
                      {
                          Uri = ConfigurationManager.ConnectionStrings["RabbitMQ"].ConnectionString,
                          RequestedHeartbeat = 15
                          //every N seconds the server will send a heartbeat.  If the connection does not receive a heardbeat within
                          //N*2 then the connection is considered dead.
                          //suggested from http://public.hudl.com/bits/archives/2013/11/11/c-rabbitmq-happy-servers/
                      };

                      var con = new AutorecoveringConnection(factory);
                      con.init();
                      return con;
                  })
        .InSingletonScope();
jhilden
  • 12,207
  • 5
  • 53
  • 76
  • thanks for the reply. Do you see any value in abstracting the rabbitmq implementation though? Id imagine it will be very difficult for you to change queue if you really needed ? – Neil Hosey May 05 '15 at 08:18
  • also could you give me a simple example of it being used then? – Neil Hosey May 05 '15 at 12:23
  • 1
    Yes, we abstract rabbit away. The code only knows about an IMessageBusProducer which it knows pushes messages to a "message bus". We can then use Rabbit, MSMQ, whatever we want. – jhilden May 05 '15 at 14:33
  • There's no reason to create a new factory every time you need a connection – MatteoSp May 06 '15 at 22:55
  • @MatteoSp This solution won't because the actual `IConnection` is registered as a singleton, once it's been created it will be reused. – Lukazoid May 06 '15 at 23:11
  • You're right, I didn't notice the `InSingletonScope()`. Just curios: a single connection for an entire application, is that enough? – MatteoSp May 07 '15 at 07:41
  • 1
    @MatteoSp yes, a single connection is rabbits recommended way. The connection will then have many channels on it. We often have 30+ channels on a single connection. – jhilden May 07 '15 at 12:35