多项目解决方案中的Autofac

时间:2018-01-03 04:19:44

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

我在C#解决方案中使用Autofac作为依赖注入系统,该解决方案跨越多个类库和多个可执行文件。我使用模块来配置Autofac,但这仍然让我遇到构建DI容器的问题,这取决于我为其组成的可执行文件。

我尝试使用Autofac的RegisterAssemblyModules,但你必须给它一个要扫描的程序集列表,并且在使用类库程序集中的某些Type之前,程序集不会被加载,因此不会可以扫描。

有些人建议加载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<>绑定系统

中的问题

在实施@ Nightowl888的建议时,我遇到了Microsoft配置IOptions<>系统的问题。以下是我尝试配置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容器的解析语义中没有硬连接的库程序集。

思考?除了&#34;放弃IOptions<>系统&#34;,我已经考虑过了,但它提供了许多我想维护的好处。

1 个答案:

答案 0 :(得分:2)

每个可执行应用程序都应具有 拥有 唯一的DI配置。 Librariesframeworks应该构建为对DI友好,但实际上并不引用任何DI容器。

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

如果您要使用autofac模块,它们应该是使用它们的应用程序的一部分,而不是包含在组件中的组件中。虽然看起来你不必在每个应用程序中重复配置代码而获得一些东西,但这样做的主要问题是它意味着你的应用程序失去了DI的一个主要好处 - 也就是说,它无法提供任何给定组件的替代实现。使库松散耦合的关键在于它允许决定如何将应用程序耦合在一起,最终由承载组件的应用程序进行。

  

宠物小便:另请注意,您拥有的项目或解决方案的数量与应用程序的运行时行为完全无关(例如它的组成方式)。项目和解决方案是一种在编译代码之前组织代码的方法 - 一旦编译代码,就没有“项目”或“解决方案”的概念,你剩下的只是“程序集”,可能依赖于其他“程序集” 。对于每个应用程序,您最终得到一个可执行文件程序集和0个或更多依赖程序集。组合根应该只存在于可执行程序集中。