8

我在这里阅读了有关该论点的各种其他问题,最值得注意的是

依赖注入(DI)“友好”库

Ioc/DI - 为什么我必须在入口应用程序中引用所有层/组件?

和这篇文章(和其他各种材料)。

但是,我不清楚在库 (DLL) .NET 项目中将组合根放在哪里。该项目不属于文章中提到的任何特定类型。在桌面、控制台甚至 Web 应用程序中,这一点被明确定义。

我目前的做法是包装容器,注册类型并重新公开 Resolve 方法:

class DefaultBootstrapper : IBootstrapper {
  public Bootstrapper() {
    _container = new XXXContainer();
    RegisterTypes(_container);
  }

  public T Resolve<T>() where T : class {
    return _container.Resolve<T>();
  }

  // + other _container.Resolve() overloads

  private readonly XXXContainer _container;
}

然后我阻止库使用者创建库的根实例(例如定义内部构造函数),从而强制使用单例工厂:

class XYZFactory {
  static XYZFactory() {}

  private XYZFactory(IBootstrapper bootstrapper) {
    _bootstrapper = bootstrapper;
  }

  public static XYZFactory Instance {
    get { return Singleton; }
  }

  public ABCType CreateABCType(string param1) {
    return _bootstrapper.Resolve<ABCType>(param1, _bootstrapper.Resolve<Dependency1>); 
  }

  private static readonly XYZFactory Singleton = XYZFactory(new DefaultBootstrapper);
  private readonly IBootstrapper _bootstrapper;
}

问题是,有更好的方法或更好的模式来定位库项目中的组合根吗?

4

1 回答 1

13

这取决于您正在创建的库的类型。您的库项目是您自己的解决方案的一部分,还是其他开发人员在您的团队、部门甚至组织之外依赖的可重用库?

如果它只是解决方案的库项目的一部分,则库项目本身通常不应包含组合根。根据定义,组合根是“模块组合在一起的应用程序中的(最好)唯一位置”。换句话说,您的解决方案将有一个或多个启动项目(例如 MVC 应用程序、WCF 服务、控制台应用程序),并且每个启动项目都将获得自己的组合根。下面的图层不会有自己的合成根。

顺便说一句,这并不意味着您不应该防止组合根内的代码重复。当包含项目(例如 DAL 和 BLL)的默认接线导致大量重复时,您通常应该将此逻辑提取到另一个项目中。您可以通过在其中一个项目(很可能是 BLL)中包含部分注册逻辑并让每个组合根调用该共享逻辑来做到这一点,或者您可以通过为该项目添加一个特殊的“引导程序”项目来做到这一点,并且引用的项目。此引导程序项目将仅包含注册逻辑。通过将此逻辑与应用程序程序集分离,您可以防止这些程序集需要对使用的依赖注入库的依赖。但是,如果程序集依赖于此类库,通常不是问题,

对于可重用的库,事情通常是不同的。在这种情况下,消费者将使用您的库,但您无法控制他们如何构建他们的应用程序。您通常希望以消费者可以直接使用的方式提供库,而不必在其组合根中进行各种“复杂”注册。您通常甚至根本不知道它们是否有组合根。

In that case you should typically make your library working without a DI container. You should yourself not take a dependency on such a container, because this would drag the container in. If you do use a container, question yourself why your reusable library uses a container, and if this has to be. Perhaps you do because you designed all types around the dependency injection principle; because this makes testing easier. Don't forget that this is your problem, not the problem of your consumers. As a reusable library designer, you should hard in getting your library as usable as possible for your consumers. Please do never assume your consumers are using a DI Container. Even if they practice Dependency Injection, they might apply Pure DI rather than a DI Container.

In case you are building a reusable library, take a look at this blog post from Mark Seemann.

于 2013-02-04T10:30:02.983 回答