找到.NET库的正确组合根

jay*_*jay 8 c# dependency-injection inversion-of-control composition

我在这里看到了关于这个论点的各种其他问题,最值得注意的是

依赖注入(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;
}
Run Code Online (Sandbox Code Playgroud)

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

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;
}
Run Code Online (Sandbox Code Playgroud)

问题是,有一种更好的方法或更好的模式用于在库项目中定位组合根

Ste*_*ven 13

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

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

这个btw并不意味着你不应该阻止组合根中的代码重复.当包含项目(例如DAL和BLL)的默认连线导致大量重复时,通常应将此逻辑提取到另一个项目.您可以通过在其中一个项目(很可能是BLL)中包含部分注册逻辑来执行此操作,并让每个组合根调用该共享逻辑,或者您可以通过为该项目添加特殊的"引导程序"项目来完成此操作,引用的项目.此引导程序项目仅包含注册逻辑.通过将此逻辑与应用程序程序集分开,可以防止这些程序集需要依赖于使用的依赖项注入库.但是,如果程序集依赖于此类库,通常不会出现问题,只要您确保应用程序逻辑不依赖于容器即可.

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

在这种情况下,您通常应该使您的库在没有DI容器的情况下工作.您自己不应该依赖于这样的容器,因为这会将容器拖入.如果您使用容器,请问自己为什么您的可重用库使用容器,如果必须这样.也许你这样做是因为你围绕依赖注入原则设计了所有类型; 因为这使测试更容易.不要忘记这是你的问题,而不是你的消费者的问题.作为可重复使用的库设计师,您应该尽可能地让您的库尽可能地为您的消费者使用.请不要假设您的消费者正在使用DI容器.即使他们练习依赖注入,他们也可能使用Pure DI而不是DI Container.

如果您正在构建可重用的库,请查看Mark Seemann撰写的这篇博客文章.