我有一个库处理与我在大多数应用程序中使用的数据库后端的交互,现在想要转换为IoC结构(在内部使用Autofac,但它的用法不应该依赖于特定的IoC容器,甚至不能使用一个人)。如何在没有应用程序处理的情况下以“默认”方式连接库的内部依赖关系,但是如果有必要可以提供其他实现?
作为示例:库可以存储和读取用户硬盘驱动器上的不同后端服务器的连接凭据。这些信息的一部分,至少是密码,是加密的,通常使用库中定义的默认加密 - 所以通常我不想关心使用该库的应用程序中的细节。但是在我的应用程序调用登录方法时,可能会出现需要提供不同加密算法(例如通过IConnectionEncryption
接口)的情况。
在我的库和我的应用程序中,我需要做什么才能实现这一目标?
答案 0 :(得分:3)
通常,希望应用程序来处理它。你自己说过 - 你想在应用程序组合根目录中进行DI容器配置(这是最佳实践)。
如果您对DI容器的任何了解不在库中,其他开发人员将能够使用他们选择的容器(或根本没有容器)。
另一方面,你最终会得到类似Rhino Service Bus的东西(大部分)取决于特定的DI容器。如果您的项目是开源的,那么您可能会收到与容器X,版本Y兼容的请求。即使它是封闭源代码,您的团队也可能希望有一天更改容器。
希望@Mark Seemann可以给出一个规范的答案。 :)
答案 1 :(得分:0)
Common Service Locator可能会对您有所帮助。它的工作是为多个IoC容器提供一个通用接口,以便您或您图书馆的其他消费者可以选择要集成的容器。
答案 2 :(得分:0)
我假设,根据您的问题标题,您的目标是从合成根配置您的库,但不要求消费应用程序知道如何为其注册所有内容。
使用Autofac执行此操作的最简单方法是创建一个或多个modules:
public class SecurityModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register<Sha256ConnectionEncryption>.As<IConnectionEncryption>();
// ...other security-related registrations...
}
}
现在,应用程序可以简单地注册模块:
// In composition root
builder.RegisterModule<SecurityModule>();
要注册接口的不同实现,您只需在注册模块后提供该注册即可。 Autofac采用最后的方式进行注册,这意味着您可以更改模块所做的任何默认决策:
// In composition root
builder.RegisterModule<SecurityModule>();
builder.Register<Sha512ConnectionEncryption>().As<IConnectionEncryption>();
这将导致在应用程序中需要Sha512ConnectionEncryption
的任何地方注入IConnectionEncryption
。