I am attempting to set up RabbitMQ for a pair of Windows Services I am writing, to facilitate communication between them in a quick and reliable way. However, I'm running into a problem when trying to set up the main windows service engines, which need to establish connections to the RabbitMQ server to do their thing.
Basically, the ConnectionFactory
object in RabbitMQ's .NET client is not abstract and implements no interfaces. I can't see an obvious way to inject this class using an IoC container like StructureMap. Even the code examples in the documentation show just blatantly new
ing it up, like so:
ConnectionFactory factory = new ConnectionFactory();
factory.Uri = "amqp://user:pass@hostName:port/vhost";
IConnection conn = factory.CreateConnection();
The solution that presents itself to me is to push up the entire factory into the service's main OnStart
and OnStop
functions, which are really difficult to test and not of huge interest anyway. However, that leaves me with a single IConnection
for the service, so if that connection is broken in any way, the service has no way to recover and must simply exit. If the main engine had visibility to the factory, it could simply produce a new connection and continue. But unless I inject that, there is no way to test the main engine without connecting to an existing server!
Is there anything I am missing here? Any other option I'm not considering? How can I go about injecting this factory, and if I can't, how can I limit the damage?
EDIT: Also, as an afterthought, I'm perfectly happy to make a change to RabbitMQ's .NET client to implement an interface on this if someone has a good idea of how receptive the main dev team would be to a change like this. I'd be delighted to contribute, but the last thing I want to do is have my programs working on some custom version of RabbitMQ, thereby eliminating the main benefit of using a third party library in the first place.
The RabbitMQ C# client is a low-level pureish AMQP implementation, you'd probably want to wrap it in some higher level abstraction and then register that with your IoC container.
EasyNetQ, a higher level abstraction over the basic client, implements a persistent AMQP connection that reconnects after a connection is lost (either through network problems, or a server bounce), and rebuilds all the current subscriptions. You're welcome to take any of that code that you find useful.
In short, it's a question of wrapping connection management in some kind of PersistentConnection class, and then registering each subscription with some code to rebuild them after a successful reconnect.
I've written a blog post on wiring up EasyNetQ, the Windsor IoC container and TopShelf. I've used this technique successfully for building RabbitMQ based windows services.
The tricky part is it looks like according to the documentation ConnectionFactory
doesn't implement any interfaces.
So you're really left with implementing your own, something like,
public interface IConnectionFactory
{
ConnectionFactory Get();
ConnectionFactory Get(string uri);
}
public class ConnectionFactoryCreator : IConnectionFactory
{
public ConnectionFactory Get(
string uri = "amqp://user:pass@hostName:port/vhost")
{
return new ConnectionFactory
{
Uri = uri
};
}
}
For the class where you end up using it,
public class RabbitMQUserClass
{
public ConnectionFactory ConnectionFactory {get; private set;}
public RabbitMQUserClass(IConnectionFactory connectionFactory)
{
ConnectionFactory = connectionFactory.Get();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With