将运行时构造函数参数传递给Autofac的最佳方法是什么?

时间:2017-08-01 00:34:44

标签: c# autofac

我正在构建一个通用的中间件软件(一个Windows服务),它将执行许多jobs ..例如:

  • 同步广告资源
  • 导入订单

我正在使用带有Windows服务的C#和Quartz.NET来安排作业运行。 我也在使用AutoFac。

根据我的理解,应该在组合根目录下构建AutoFac依赖项。这很好..但是,我有一些需要运行时参数的注入服务(配置值来自数据库)。

例如:

  • 某些作业将连接到SFTP服务器,从而将连接详细信息存储为数据库中的键值对
  • 某些作业将连接到远程API,从而根据数据库中的作业存储这些API身份验证详细信息。

我已经对此做了一些研究,一些替代方案基本上建议删除其中一些服务的构造函数(例如SFTP客户端)并将它们作为配置方法传递。

而不是客户端有一个构造函数,如

SftpClient(string host, string username, string password, int timeoutInSeconds)

它将有一个默认构造函数,以及你传递它们的configure方法。

我根本不喜欢这样 - 它违背了我所学到的,你应该尝试配置你的对象,使它通过构造函数处于一致状态。

最好的选择是什么? 我的JobFactory方法目前依赖于IComponentContext。 我已经看到有办法将参数传递给AutoFac来构建对象,但我读过的东西表明它并不理想。 是否更好地使用我的工厂

2 个答案:

答案 0 :(得分:2)

最简单的解决方案是注入工厂而不是实例。不要注入AutoFac容器本身(隐藏依赖项)。只写一个简单的类。

class SftpClientFactory : ISftpClientFactory
{
    public SftpClient GetClient(string host, string userName, string password, int timeout)
    {
        return new SftpClient(host, userName, password, timeout);
    }
}

然后像这样注册:

container.RegisterType<ISftpFactory, SftpFactory>();

在你的课堂上

class Example
{
    private readonly ISftpClientFactory _clientFactory;

    public Example(ISftpClientFactory injectedFactory)
    {
        _clientFactory = injectedFactory;
    }

    public void DoTheWork()
    {
        var client = _clientFactory.GetClient(host, userName, password, timeout);
    }
}

作为奖励,您现在可以完全控制对象生命周期,这对于sftp客户端来说可能很重要,该客户端可能拥有非托管资源并且Disposable

    public void DoTheWork()
    {
        using (var client = _clientFactory.GetClient(host, userName, password, timeout))
        {
            client.DownloadFile();
        } 
    }

此方案保留了控制的反转,您仍然保留单个组合根,客户端仍然可以由您的单元测试项目存根,并且您仍然可以获得依赖项的编译时解析。唯一的缺点是编写存根稍微多一点,因为你也必须编写一个存根工厂。

答案 1 :(得分:0)

您可以利用delegate factories在运行时传递自定义参数。在这种情况下,您不必创建任何自定义工厂,并且在测试中也很容易进行模拟。

您不能使用内置Func<X,Y,T>委托,因为您必须传递的参数属于同一类型。但是你可以介绍自己的代表。如果您有SmtpClient的单独界面,它将如下所示

public delegate ISmtpClient SmtpClientFactory(string host, string username, string password, int timeout);

然后,您应该注入ISmtpClient而不是注入SmptClientFactory。那里不需要额外的注册。

如果你没有ISmtpClient界面,它看起来几乎一样,虽然以后测试会更难。