模块是Autofac的绑定上下文

时间:2012-02-01 10:11:47

标签: c# .net dependency-injection ioc-container autofac

我有一个可能需要连接到多个数据库的应用程序。但每个模块只能连接一个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));
    }
}

2 个答案:

答案 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) )); 实例。

反政府:

  1. 这是很多代码
  2. 它不会使IA组件“内部”到模块 - 其他模块仍然可以使用简单的IA来解决它。模块不是孤立的。
  3. 希望这有帮助

    <强>更新

    在某些情况下,从设计的角度来看,它可能更容易,而且坦率地说更正确:

    委派注册

    Resolve<IA>

    优点:

    1. 您不会将特定于模块的builder.Register(ctx => new CB(new CA { Name = "Two" })) .Named("Two", typeof(CB)); 公开给其他模块
    2. 反政府:

      1. 如果CACA具有复杂的依赖关系和许多构造函数参数,那么最终会导致构造代码的混乱
      2. 如果您需要在模块内的多个位置使用CB,则必须找到避免复制粘贴的方法
      3. 嵌套容器实例

        另一种选择是在每个模块中都有一个独立的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解析的实例。