找到.NET库的正确组合根

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

dependency injection(DI)“友好”库

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

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

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

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

class DefaultBootstrapper : IBootstrapper { public Bootstrapper() { _container = new XXXContainer(); RegisterTypes(_container); } public T Resolve() where T : class { return _container.Resolve(); } // + 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(param1, _bootstrapper.Resolve); } private static readonly XYZFactory Singleton = XYZFactory(new DefaultBootstrapper); private readonly IBootstrapper _bootstrapper; } 

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

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

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

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

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

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

如果您正在构建可重用的库,请查看Mark Seemann的博客文章。