我有一个可能需要连接到多个数据库的应用程序。但每个模块只能连接一个db。所以我认为将db分离到每个模块可能是有意义的,这样每个模块都会自动解析自己的db,我不需要为命名注册而烦恼。但令我惊讶的是,似乎Autofac的模块更像是一个代码模块而不是逻辑模块(我在这里错了吗?):IA
[Test]
public void test_module_can_act_as_scope_container()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterModule(new Module1());
IContainer c = builder.Build();
var o = c.ResolveNamed<CB>("One");
Assert.That(o.A.Name, Is.EqualTo("One"));
builder = new ContainerBuilder();
builder.RegisterModule(new Module1());
builder.RegisterModule(new Module2());
c = builder.Build();
var t = c.ResolveNamed<CB>("One");
Assert.That(t.A.Name, Is.EqualTo("Two"));
}
使用的接口/模块:
public interface IA
{
string Name { get; set; }
}
public class CA : IA
{
public string Name { get; set; }
}
public class CB
{
public CB(IA a)
{
A = a;
}
public IA A { get; private set; }
}
public class Module1 : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(c => new CA() { Name = "One" }).As<IA>();
builder.RegisterType<CB>().Named("One", typeof(CB));
}
}
public class Module2 : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.Register(c => new CA() { Name = "Two" }).As<IA>();
builder.RegisterType<CB>().Named("Two", typeof(CB));
}
}
答案 0 :(得分:2)
是的,你是对的。
模块仅用于将配置拆分为某些独立的部分。它们不以任何方式配置范围。拥有模块实际上就像将所有模块的“Load
方法”代码合并到一个配置方法中然后构建容器一样。
在您的情况下,Module2
实际上覆盖了来自IA
的{{1}}界面的注册。
我也有兴趣找到问题的解决方案。我采用以下方法:
键控服务
Module1
优点:
您可以控制在每个模块中注入哪些var key = new object();
builder.Register(c => new CA() { Name = "Two" }).Keyed<IA>(key);
builder.RegisterType<CB>().Named("Two", typeof(CB))
.WithParameter(new ResolvedParameter(
(pi, ctx) => pi.Type == typeof(IA),
(pi, ctx) => ctx.ResolveKeyed<IA>(key)
));
实例。
反政府:
IA
组件“内部”到模块 - 其他模块仍然可以使用简单的IA
来解决它。模块不是孤立的。希望这有帮助
<强>更新强>
在某些情况下,从设计的角度来看,它可能更容易,而且坦率地说更正确:
委派注册
Resolve<IA>
优点:
builder.Register(ctx => new CB(new CA { Name = "Two" }))
.Named("Two", typeof(CB));
公开给其他模块反政府:
CA
和CA
具有复杂的依赖关系和许多构造函数参数,那么最终会导致构造代码的混乱CB
,则必须找到避免复制粘贴的方法嵌套容器实例
另一种选择是在每个模块中都有一个独立的CA
。这样,所有模块都可以拥有其私有容器配置。但是,AFAIK,Autofac不提供任何内置方法以某种方式链接多个Container
实例。虽然我认为实施这个应该不是很困难。
答案 1 :(得分:1)
您可以使用nestet生命周期范围。这些形成了一个层次结构,其中子范围可以解析在超级作用域中注册的服务。此外,您可以在每个子范围中注册唯一服务,如下所示:
var cb = new ContainerBuilder();
cb.RegisterModule<CommonModule>();
var master = cb.Build();
var subscope1 = master.BeginLifetimeScope(cb2 => cb2.RegisterModule<Module1>());
var subscope2 = master.BeginLifetimeScope(cb2 => cb2.RegisterModule<Module2>());
通过此设置,Module1
中的服务仅适用于从subscope1
解析的实例。