4

考虑我有一个使用三个库 lib1、lib2 和 lib3 的应用程序。在每个库中,我实现了一个Module注册在该库中实现的依赖项的库。

其中一些实现有自己的依赖关系,例如,lib2 和 lib3 可能都需要一些存在于 lib1 中的实现。

我的问题是,我是否让 lib2 和 lib3 中的模块在 lib1 中注册模块作为其Load实现的一部分?如果我的应用注册了 lib2 和 lib3 的模块,这是否会注册该模块两次?

或者我是否避免让一个模块注册另一个模块,将其留给应用程序,缺点是启动时可能会丢失一些注册?

4

4 回答 4

5

我知道有点晚了,但我认为回答这个问题可能会很好,而不是仅仅引用关于多个组合根源如何邪恶的经文......

如果我的应用注册了 lib2 和 lib3 的模块,这是否会注册该模块两次?

使用 Autofac 4.8.1 测试,它确实:

public class Lib1Module: Module
{
    protected override void Load(ContainerBuilder builder)
    {
        Console.WriteLine("Registering Lib1Module");

        // Register Types...

    }
}

public class Lib2Module: Module
{
    protected override void Load(ContainerBuilder builder)
    {
        Console.WriteLine("Registering Lib2Module");

        builder.RegisterModule<Lib1Module>();

        // Register Types...

    }
}

public class Lib3Module: Module
{
    protected override void Load(ContainerBuilder builder)
    {
        Console.WriteLine("Registering Lib3Module");

        builder.RegisterModule<Lib1Module>();

        // Register Types...

    }
}

public class Program
{
    public void Main(string[] args)
    {
        var builder = new ContainerBuilder();
        builder.RegisterModule<Lib2Module>();
        builder.RegisterModule<Lib3Module>();

        using(var container = builder.Build())
        {
            // Do Stuff
        }
    }
}

输出:

Registering Lib2Module
Registering Lib1Module
Registering Lib3Module
Registering Lib1Module

IComponentRegistry您可以在/上使用 Properties 字典ContainerBuidler(基类在内部使用 -source的属性Module创建它传递给的 Container 构建器)解决此问题并强制对模块进行单一注册,如果Method of更改为:LoadIComponentRegistryLoadLib1Module

protected override void Load(ContainerBuilder builder)
{
    if (builder.Properties.ContainsKey(GetType().AssemblyQualifiedName))
    {
        return;
    }
    builder.Properties.Add(GetType().AssemblyQualifiedName, null);

    Console.WriteLine("Registering Lib1Module");

    // Register Types...

}

然后输出变为:

Registering Lib2Module
Registering Lib1Module
Registering Lib3Module

显然,如果 Lib2Module/Lib3Module 可以成为其他模块的依赖项,则必须将类似的代码放入它们的 Load 方法中,并且类似地,如果使用任何模块AttachToRegistrationSource和/或 AttachToComponentRegistration希望确保它们仅在它们也需要检查时运行。或者(如果这是您需要做的很多事情,可能最好)您可以创建自己的类实现IModule并在Configure.

我肯定在生产代码中使用了这种模式来减少重复量,因为我有多个入口点,它们有自己的组合根(例如,Web api、Web 应用程序和重复出现的控制台应用程序),但它们共享很大一部分代码,我可以忍受这使我成为 DI 纯粹主义者中不受欢迎的角色。

于 2018-06-27T11:07:13.627 回答
1

我不建议在您的图书馆内进行注册。在大多数情况下,您应该有一个组合根来组合您的所有应用程序。

组合根是模块组合在一起的应用程序中的(最好)唯一位置。

这个概念在这里解释composition root

顺便说一句,如果您多次注册一个模块,Autofac将多次注册组件。如果您的库中必须有模块,您应该只创建注册库组件的模块。

于 2016-10-18T11:51:27.633 回答
1

一般来说,应该只有一个库包含配置。这个库是启动项目,应用程序中连接所有内容的这个地方通常称为Composition Root。通常只有启动项目具有组合根,并且只有当单个解决方案中的多个启动项目共享大量重复注册时,您才开始将此代码提取到这些组合根可以重用的公共位置。但要小心:一般而言,不应重复使用 Composition Roots

于 2016-10-18T11:45:21.663 回答
0

Autofac 只不过Module是帮助注册组件的外观。它不应该为了注册已知是其自己注册的依赖关系的实现而调用其他模块,因为这会将两个模块联系在一起,增加耦合。

此外,如果同一个模块被多次注册,则注册本身会被多次应用,因为 Autofac 不会跟踪已经注册的模块。这通常不会造成问题,除非组合根无意中使任何旨在覆盖现有注册的注册无效。

于 2016-11-02T11:19:50.263 回答