我有一个应用程序,它使用两个不同的模块(实现为Autofac.Module(来注册它们提供的服务。每个都有一个适配器,用于通过不同方法生成相同数据的硬件设备。
public class AdapterA : IDataProducer {
public AdapterA(IConfigSource conf){
// do something with conf, like setting an IP address, port etc.
}
}
public ModuleA : Module{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<AdapterA>().As<IDataProducer>();
// the config source is specific to Module A, as it contains details about the hardware
builder.Register(c => new IniConfigSource("moduleA.ini")).As<IConfigSource>();
}
}
现在,当我在主应用程序中注册该模块时,它运行良好,依赖关系也得到了正确解决。
builder.RegisterModule<ModuleA>();
在我的主应用程序中,我还使用IConfigSource
来读取/写入特定于应用程序的设置。当我用不同的设置文件在那里注册另一个IConfigSource
时,问题就变得显而易见了。
protected override void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule<ModuleA>();
builder.Register(c => new IniConfigSource("mainprogram.ini")).As<IConfigSource>();
}
在Resolution时,第二次注册生效,并且我的ModuleA
接收到错误的配置文件读取器。
四处寻找解决方案,我试图通过更改注册类型来解决这个问题,如下所示:
public interface IModuleAConfigSource : IConfigSource {}
和
builder.Register(c => new IniConfigSource("moduleA.ini")).As<IModuleAConfigSource>();
但这并不奏效。Autofac在解析时抱怨类型IniconfigSource
无法分配给接口IModuleAConfigSource。在应用程序启动时,我在单个函数中使用带有注册的构造函数注入。
在这里什么是好的策略?我知道我可以使用具体的类型来解决这个问题,但有没有办法将注册模块保持在本地,即在解析类型以使用该模块的注册时?
经过更多的阅读,我认为键控服务注册对我来说是可行的。我用模块专用密钥注册IConfigSource
,如下所示:
builder.Register(c => new IniConfigSource("moduleA.ini")).Keyed<IConfigSource>("moduleA");
以及取决于服务的类型为:
builder.RegisterType<ConcreteModuleAType>().AsSelf().WithAttributeFiltering();
ConcreteModuleAType
的构造函数具有属性
public ConcreteModuleAType([KeyFilter("moduleA")] IConfigSource configSource) {
this.configSource = configSource;
}
这对我来说是一个很好的解决方案。唯一的问题是模块注册的顺序很重要。模块必须最后注册,因为显然非键控注册会覆盖键控注册。