RabbitMQ: 注入连接工厂

7
我正在尝试为我编写的一对Windows服务设置RabbitMQ,以便在它们之间实现快速可靠的通信。然而,在尝试设置主要的Windows服务引擎时,我遇到了一个问题,这些引擎需要建立与RabbitMQ服务器的连接以完成它们的任务。
基本上,RabbitMQ的.NET客户端中的ConnectionFactory对象不是抽象的,并且没有实现任何接口。我无法找到一种明显的方法来使用像StructureMap这样的IoC容器注入这个类。即使是文档中的代码示例也只是简单地使用new关键字创建它,如下所示:
 ConnectionFactory factory = new ConnectionFactory();
 factory.Uri = "amqp://user:pass@hostName:port/vhost";
 IConnection conn = factory.CreateConnection();

我想到的解决方案是将整个工厂推入服务的主要 OnStartOnStop 函数中,这些函数非常难以测试并且不太有趣。然而,这样会让我只有一个IConnection用于服务,因此如果该连接出现任何问题,服务将无法恢复并必须退出。如果主引擎能够看到工厂,它可以简单地生成一个新的连接并继续运行。但是,除非我注入它,否则没有办法在连接到现有服务器的情况下测试主引擎!
还有其他选项吗?我是否遗漏了什么?如何注入此工厂,如果无法注入,如何限制损坏?
另外,作为补充,如果有人有一个很好的想法,关于RabbitMQ的.NET客户端实现接口的更改,我也很乐意做出贡献,但我最不想做的事情就是让我的程序在某个自定义版本的RabbitMQ上运行,从而消除使用第三方库的主要好处。
2个回答

7

RabbitMQ C#客户端是一个低级别的、纯AMQP实现,您可能希望将其包装在一些更高级别的抽象中,然后将其注册到IoC容器中。

EasyNetQ是基本客户端的更高级别的抽象,实现了一个持久化的AMQP连接,在连接丢失后重新连接(无论是通过网络问题还是服务器反弹),并重建所有当前的订阅。您可以使用任何您觉得有用的代码。

简而言之,这是一个将连接管理包装在某种PersistentConnection类中的问题,然后注册每个订阅以一些代码重建它们,以便在成功重新连接后使用

我已经写了一篇关于如何连接EasyNetQ、Windsor IoC容器和TopShelf的博客文章(链接在此)。我成功地使用这种技术构建了基于RabbitMQ的Windows服务。


我将会热切地调查这个问题。如果它像我所希望的那样好,我将会更改这里的被接受答案,并向M Afifi道歉。 - tmesser
当尝试通过NuGet包安装EasyNetQ时,它坚持认为我已经引用了一个更新的RabbitMQ.Client版本,即使我完全删除了旧引用。有任何想法为什么? - tmesser
EasyNetQ 坚持认为我已经引用了更新的版本。你能具体说明一下吗?这是运行时程序集绑定问题还是 NuGet 抱怨呢? - Mike Hadlow
抱歉 - NuGet 出了问题。我看到的具体输出是:成功安装 'RabbitMQ.Client 2.8.6'。 成功安装 'Newtonsoft.Json 4.5.10'。 成功安装 'EasyNetQ 0.8.1.37'。 安装失败。正在回滚... 已经引用了较新版本的 'RabbitMQ.Client'。 - tmesser
我建议您尝试删除所有NuGet相关的内容,包括每个项目中的packages.config文件以及解决方案根目录下的Packages文件夹。然后重新启动NuGet并重新添加所有内容。 - Mike Hadlow
显示剩余2条评论

6

麻烦之处在于根据文档,看起来ConnectionFactory没有实现任何接口。

因此,你只能自己实现一个,类似于以下内容:

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

对于使用它的类

public class RabbitMQUserClass
{
    public ConnectionFactory ConnectionFactory {get; private set;}
    public RabbitMQUserClass(IConnectionFactory connectionFactory)
    {
        ConnectionFactory = connectionFactory.Get();
    }
}

我想记录下来,我非常不喜欢这个解决方案,但你绝对正确,这是我在目前情况下唯一的选择。感谢你的时间和帮助。 - tmesser

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接