c# - Module 是 Autofac 的绑定(bind)上下文吗

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

我有一个应用程序可能需要连接到多个数据库。但是每个模块只会连接到一个数据库。所以我认为将数据库隔离到每个模块中可能是有意义的,这样每个模块都会自动解析自己的数据库,我不需要为命名注册而烦恼。但令我惊讶的是,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"));
}

以及使用的接口(interface)/模块:

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));
    }
}

最佳答案

是的,你是对的。

模块仅用于将配置拆分为一些独立的部分。它们不以任何方式限定配置范围。拥有模块实际上与合并所有模块相同 Load方法的代码合并到一个配置方法中,然后构建容器。

在你的情况下你的 Module2实际上覆盖了 IA 的注册来自 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实例将被注入(inject)到每个模块中。

对比:

  1. 代码很多
  2. 它不会生成IA组件“内部”到模块 - 其他模块仍然可以使用简单的 Resolve<IA> 解析它.模块不是孤立的。

希望对你有帮助

更新

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

代表注册

builder.Register(ctx => new CB(new CA { Name = "Two" }))
  .Named("Two", typeof(CB));

优点:

  1. 您没有公开您的模块特定 CA到其他模块

对比:

  1. 如果CACB有复杂的依赖关系和大量的构造函数参数,你最终会得到一堆乱七八糟的构造代码
  2. 如果您需要使用CA在模块内的多个位置,您必须找到避免复制粘贴的方法

嵌套容器实例

还有一个选择是拥有一个独立的 Container在每个模块内。这样所有模块都可以拥有自己的私有(private)容器配置。但是,据我所知,Autofac 不提供任何内置方法以某种方式链接多个 Container实例。虽然我认为实现这个应该不是很困难。

关于c# - Module 是 Autofac 的绑定(bind)上下文吗,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9094057/

相关文章:

c# - WPF - 将带有字符串列表的类绑定(bind)到 ListBox

c# - 创建 WiFi 应用程序

c# - 日期时间.ParseExact : "String not recognised as a valid DateTime"

c# - 我可以强制子类重写一个方法而不使它抽象吗?

c# - 购物车和 Paypal 是两个不同的东西吗?

database - 如何在单元测试中伪造 SqlDataAdapter、SqlConnection 和 SqlCommand

.net - 工作单位模式

java - 如何在 LibGDX 中正确使用 Dagger 2 的场注入(inject)?

c# - 延迟定时器循环

c# - 为什么我不能将 Debug.Assert() 与接受动态并返回 bool 的方法一起使用?