组件架构和DI容器的使用?

时间:2012-12-12 15:44:00

标签: .net oop architecture dependency-injection unity-container

我有一个FTP实用程序,负责通常的FTP工作:放置文件,获取文件等。作为我们基础架构的一部分,我们要求组件从实现IConfiguration接口的组件检索其配置并将其条目记录到实现ILogger接口的组件。请注意,ftp主机是通过logicalHost名称(例如someFtpSite)描述的,该名称与配置文件中包含主机名,用户ID和密码的部分相匹配。所以我的界面和类定义是这样创建的:

public interface IFtpUtility
{
    void PutFile(string sourceFileAndPath, string targetFileAndPath, string logicalHost);
}

public class FtpUtility : IFtpUtility
{
    private readonly IConfiguration _configuration;
    private readonly ILogger _logger;

    public FtpUtility(ILogger logger, IConfiguration configuration)
    {
        _configuration = configuration;
        _logger = logger;
    }
    // IFtpUtility implementation follows
}

我对此签名的意图是只在需要操作时才需要logicalHost名称(例如PutFile),因此在PutFile方法本身上提供它。

这种布局非常适合与Unity等IoC容器一起使用。我们将拥有以下代码:

UnityContainer = new UnityContainer();
UnityContainer.RegisterType<IConfiguration, ConfigurationProvider>();
UnityContainer.RegisterType<ILogger, LoggingProvider>();
UnityContainer.RegisterType<IFtpUtility, FtpUtility>();

稍后我需要使用FtpUtility时,我会依靠容器进行适当的分辨率:

IFtpUtility ftpUtility = UnityContainer.Resolve<FtpUtility>();

现在一位同事告诉我,logicalHost名称应该是构造函数的一个参数,因为没有它,没有任何函数可以执行,它或多或少与FtpUtility的特定实例相关联。我们只会在每次调用时与一个FTP服务器进行通信。所以我很高兴地将构造函数更改为包含logicalHost名称,这破坏了我的IoC容器分辨率。 请注意,虽然IConfiguration和ILogger可以与特定实现相关联,但logicalHost特定于实例,我们在创建实例之前不知道它。现在我可以争辩说这样的改变会改变我的IoC容器使用情况,因此我无法实现它等等,但是这个参数太弱了(我发现)。以下是问题:

  • 从架构的角度来看,是否将构造函数中的logicalHost放在一个好东西上?
  • logicalHost名称是否为必需的构造参数,如果FtpUtility无法运行,因此应该是构造函数的一部分?
  • 有没有办法通过Unity解决这个问题?如果构造函数包含logicalHost的第三个参数,Resolve&lt;&gt;()是否有重载,这将允许我在解析时提供第三个参数的值,而不是提前在容器中注册?
  • 我是否尝试解决没有问题的问题?在这种情况下使用IoC容器是否过度杀伤而不是帮助,使问题复杂化?毕竟,我仍在使用IoC模式 - 只是无法自动或干净地使用IoC容器解决它?

2 个答案:

答案 0 :(得分:1)

1,2。从抽象的角度来看,在构造函数中使用主机名是合乎逻辑的,也是理想的位置。

3,4。在我个人看来,通过统一解析主机名有点矫枉过正,但完全有可能。一个更简单的选择是实例化这是你的统一配置并从标准的app / web.config中提取主机名,类似于下面的(MVC实现);

 container.RegisterType<IFtpUtility, FtpUtility>(
      new InjectionConstructor(ConfigurationManager.AppSettings["Hostname"]));

这可以很好地解耦,并且仍然允许您根据需要配置该设置。

答案 1 :(得分:1)

您可以使用以下定义解析IFtpUtility,而不是直接解析IFtpUtilityFactory

interface IFtpUtilityFactory
{
    IFtpUtility Create(string logicalHost);
}

任何给定的FTP实用程序实现都有相应的工厂实现。它实际上是一个带有通用接口的代理构造函数,可以在解决时间之后提供所需的参数。