【问题标题】:Autofac in a Multi-Project Solution多项目解决方案中的 Autofac
【发布时间】:2018-01-30 22:49:48
【问题描述】:

我在跨多个类库和多个可执行文件的 C# 解决方案中使用 Autofac 作为依赖项注入系统。我正在使用模块来配置 Autofac,但这仍然给我留下了构建 DI 容器的问题,这取决于我为哪个可执行文件编写它。

我尝试使用 Autofac 的 RegisterAssemblyModules,但您必须为其提供要扫描的程序集列表,并且在使用类库程序集中的某些类型之前,该程序集不会加载,因此无法扫描。

有些人建议加载 bin 目录中可能包含 Autofac 模块定义的每个程序集。但这似乎带来了不受欢迎的装配被投入行动的风险。

所以我想出的是这个静态类,它定义在一个通用的类库中:

public static class Container
{
    private static IContainer _instance;
    private static Dictionary<string, Assembly> _moduleAssemblies = new Dictionary<string, Assembly>();

    public static void RegisterAutofacModuleAssembly<T>()
        where T : class
    {
        var assembly = typeof(T).Assembly;

        if( !_moduleAssemblies.ContainsKey( assembly.FullName ) )
            _moduleAssemblies.Add( assembly.FullName, assembly );
    }

    public static IContainer Instance
    {
        get
        {
            if( _instance == null )
            {
                var builder = new ContainerBuilder();

                builder.RegisterAssemblyModules( _moduleAssemblies.Select( ma => ma.Value ).ToArray() );

                _instance = builder.Build();
            }

            return _instance;
        }
    }
}

您可以通过在应用程序的启动代码中包含这样的行来使用它:

public static void Main(string[] args)
{
  AutoFacRegistrar.Container.RegisterAutofacModuleAssembly<ScannerApp>(); 
  AutoFacRegistrar.Container.RegisterAutofacModuleAssembly<AppConfiguration>();

这是一个合理的解决方案吗?如果有更好、更灵活的,我有兴趣了解它。

IOptions&lt;&gt; 绑定系统中的问题

在执行@Nightowl888 的建议时,我遇到了Microsoft 配置IOptions&lt;&gt; 系统的问题。以下是我尝试配置 Autofac 以解析 AppConfiguration 对象的方式:

protected override void Load( ContainerBuilder builder )
{
    base.Load( builder );

    var config = new ConfigurationBuilder()
        .AddJsonFile( AppConfiguration.WebJobsConfigFile, false )
        .AddUserSecrets<ConfigurationModule>()
        .AddEnvironmentVariables()
        .Build();

    builder.Register<AppConfiguration>( ( c, p ) =>
        {
            var retVal = new AppConfiguration( c.Resolve<ILogger>() );

            config.Bind( retVal );

            return retVal;

        } )
        .SingleInstance();
}

问题发生在对 Bind() 的调用中。在遍历和解析配置信息的过程中,它期望通过无参构造函数来创建各种对象……这使得构造函数注入的使用变得困难。

如果我不能使用构造函数注入,我需要能够在构造函数代码中解析 DI 容器。我不明白如何定义一个不会硬连线到特定 DI 容器的解析语义中的库程序集。

想法?除了我考虑过的“放弃IOptions&lt;&gt; 系统”之外,它提供了许多我想保持的好处。

【问题讨论】:

    标签: c# dependency-injection .net-core autofac autofac-module


    【解决方案1】:

    每个可执行应用程序都应该有其自己的独特的 DI 配置。 Librariesframeworks 应构建为对 DI 友好,但实际上不引用任何 DI 容器。

    组合根是应用程序的配置。在应用程序之间共享它类似于在应用程序之间共享.config 文件——也就是说,通常不会这样做。见Composition Root Reuse

    如果您要使用 autofac 模块,它们应该是使用它们的应用程序的一部分,而不是与正在组合的组件一起包含在程序集中。虽然您似乎通过不必在每个应用程序中重复配置代码而获得了一些东西,但这样做的主要问题是这意味着您的应用程序已经失去了 DI 的主要好处之一——也就是说,它不能提供任何给定组件的替代实现。使库松散耦合的全部意义在于,它允许最终由托管组件的应用程序决定应用程序如何耦合在一起。

    小毛病:还要注意,您有多少项目或解决方案与应用程序的运行时行为(例如它的组成方式)完全无关。项目和解决方案是在编译代码之前组织代码的一种方式——一旦代码被编译,就没有“项目”或“解决方案”的概念,剩下的只是可能依赖于其他“程序集”的“程序集” .对于每个应用程序,您最终都会得到一个 executable 程序集和 0 个或更多相关程序集。组合根应该只存在于可执行程序集中。

    【讨论】:

    • 谢谢,这很有帮助。但是在尝试实施这种方法时,我遇到了我在原始问题的附录中描述的问题。我很想知道你对解决这个问题的想法。
    • 抱歉,我还没有机会使用IOptions&lt;&gt; 功能。我建议提出一个新问题,因为这个问题的答案本身就很有趣。
    • 感谢您的建议,但我可能会传递它。自从我们“说话”以来,我重写了配置例程,以便它可以利用 Microsoft 的配置系统,但不需要 DI,除了“最上层”配置类(我最初的问题是我试图通过Serilog ILogger 实例通过配置类,所以当我对它们执行验证时,他们会记录他们遇到的任何问题)。
    猜你喜欢
    • 2016-05-17
    • 1970-01-01
    • 2014-03-19
    • 2014-05-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-25
    相关资源
    最近更新 更多