【问题标题】:Howto use external plugins via config file (runtime configuration) with Autofac 5如何通过 Autofac 5 的配置文件(运行时配置)使用外部插件
【发布时间】:2020-06-03 07:45:56
【问题描述】:

我正在尝试设置一个使用 Autofac 5 IoC Container 的简单 .NET Core 3.1 项目。

我添加了对最新 Autofac.Configuration 5.0.0 package 的引用。

我已经使用简单的 JSON 配置创建了接口、实现和测试应用程序(遵循this guide):

{
  "components": [
    {
      "type": "Implementations.ImplementationN, Implementations",
      "services": [
        {
          "type": "Interfaces.InterfaceN, Interfaces"
        }
      ]
    }
  ]
}

我使用以下代码(根据相同的指南):

using Interfaces;
using Autofac;
using Autofac.Configuration;
using Microsoft.Extensions.Configuration;
using System;

------------------------
var config = new ConfigurationBuilder();
config.AddJsonFile("config.json");

var module = new ConfigurationModule(config.Build());

var builder = new ContainerBuilder();    
builder.RegisterModule(module);

var container = builder.Build();
------------------------

但我得到 System.InvalidOperationException

类型“Implementations.ImplementationN, Implementations” 找不到。它可能需要组装资格, 例如“我的类型,我的程序集”

我已将我的代码上传到GitHub。任何帮助表示赞赏。

P.S. Visual Studio 2019 16.4.5 企业版、Windows 10 1909 x64 专业版

更新:为了澄清更多 - 我的最终目标是让 Interfaces.dll 没有特殊参考,Implementations.dll 参考仅 Interfaces.dllTest.exe 仅参考 Interfaces.dll(当然还有 Autofac 包)。我希望 Autofac 通过反射从特定程序集(在 config.json 中指定)加载特定类。 Unity Container 可以做到这一点,我希望 Autofac IoC 也能做到这一点。

再一次:我需要一个没有任何项目引用 Implementations.dll 的方法,我应该能够更改特定的实现(通过更改 config.json)而无需重新编译。

【问题讨论】:

  • 您从未在任何地方注册类型,也没有要加载的模块。最好通过程序集加载模块,并将类型的注册放在单独的模块中
  • 你的意思是像builder.RegisterType<ImplementationN>().As<InterfaceN>();这样的东西吗?但是包含这段代码的库(我们将其命名为 fabric library)应该引用 Implementation.dll,对吗?当我使用 Unity Container fabric library 时,应该只引用 Interface.dll - 所有配置都是配置文件。 Autofac IoC 可以吗?
  • 是的,可以这样做。你必须这样做:c# public class ImplementationModule : Module { protected override void Load(ContainerBuilder builder) { builder.RegisterType<ImplementationN>().As<InterfaceN>(); } } ImplementationModule 应该在 implementations 项目中。我认为 config.json 文件不正确。见autofaccn.readthedocs.io/en/latest/configuration/…
  • 但是对于那个方法 实现库 应该引用 Aurofac.dll - 当我使用 Unity 时,这是不必要的。好的,我已经尝试过这种方法:将 ImplementationModule.cs 添加到实施项目并将 config.json 更改为 { "modules": [ { "type": "Implementations.ImplementationModule, Implementations" } ] }。同样的错误 - 找不到类型“Implementations.ImplementationModule, Implementations”。它可能需要装配资格,例如“我的类型,我的程序集”

标签: c# .net-core dependency-injection inversion-of-control autofac


【解决方案1】:

问题是主项目正在寻找您在 config.json 文件中输入的类型,但它没有对 implementations 项目的引用,因此它不会找到该模块。我的解决方案是,首先添加对 implementations 项目的引用,然后在 implementations 项目中创建一个 autofac 模块(您需要在 implementations 项目中使用 autofac 库,因此最好为所有项目拥有一个共享内核或简单地共享项目):

public class ImplementationModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterType<ImplementationN>().As<InterfaceN>();
        }
    }

您对实施项目的所有注册都在这里。 然后像这样更改 config.json 文件:

{
  "modules": [
    {
      "type": "Implementations.ImplementationModule, Implementations"
    }
  ]
}

那么一切都会好起来的。
如果您不想让主项目引用实施项目,则需要添加一些新项目来注册应用程序的所有模块。它还应该引用所有项目。

【讨论】:

  • 正如我在上面写的那样,我已经完全尝试了该代码 - GutHub 。相同的异常,直到我在测试应用程序中添加对 Implementations.dll 的引用。但我的目标不是有那个参考。更新了我的问题以获取更多信息。
  • 再一次:我需要在没有任何项目引用 Implementations.dll 的情况下进行改进,我应该能够更改特定的实现(通过更改 config.json) 无需重新编译。
  • 我认为您应该添加一些解决方法,例如自己加载程序集。我在运行您的项目时遇到问题。让我再次检查一下是否可以手动加载程序集
  • 您在运行我的项目时遇到了什么问题?我刚刚在一台单独的 PC 上尝试过 - 它可以毫无问题地编译和调试..
  • 当我运行您的项目时,它会立即完成并显示 **Process finished with exit code 0. ** 没有让我调试或其他任何东西。
【解决方案2】:

我发现这更像是“.NET Core 程序集加载”问题,而不是 Autofac 问题。

长话短说,如果您的应用程序没有特别引用程序集,您需要告诉 .NET Core 程序集加载器从哪里获取它即使它在您的 BIN 文件夹中

因此,如果您(像我一样)不希望有一个引导库来引用您需要的 所有 实现库,但您希望通过配置文件进行运行时配置 - 您应该执行以下操作.

来自Autofac examples

// THIS IS THE MAGIC!
// .NET Core assembly loading is confusing. Things that happen to be in your bin folder don't just suddenly
// qualify with the assembly loader. If the assembly isn't specifically referenced by your app, you need to
// tell .NET Core where to get it EVEN IF IT'S IN YOUR BIN FOLDER.
// https://stackoverflow.com/questions/43918837/net-core-1-1-type-gettype-from-external-assembly-returns-null
//
// The documentation says that any .dll in the application base folder should work, but that doesn't seem
// to be entirely true. You always have to set up additional handlers if you AREN'T referencing the plugin assembly.
// https://github.com/dotnet/core-setup/blob/master/Documentation/design-docs/corehost.md
//
// To verify, try commenting this out and you'll see that the config system can't load the external plugin type.
var executionFolder = Path.GetDirectoryName(typeof(Program).Assembly.Location);
AssemblyLoadContext.Default.Resolving += (AssemblyLoadContext context, AssemblyName assembly) =>
{
     // DISCLAIMER: NO PROMISES THIS IS SECURE. You may or may not want this strategy. It's up to
     // you to determine if allowing any assembly in the directory to be loaded is acceptable. This
     // is for demo purposes only.
     return context.LoadFromAssemblyPath(Path.Combine(executionFolder, $"{assembly.Name}.dll"));
 };

然后是以下代码:

 var config = new ConfigurationBuilder()
     .AddJsonFile("autofac.json")
     .Build();
 var configModule = new ConfigurationModule(config);
 var builder = new ContainerBuilder();
 builder.RegisterModule(configModule);
 var container = builder.Build();

工作就像一个魅力。

P.S.更多信息来自Microsoft

【讨论】:

    猜你喜欢
    • 2020-06-02
    • 2013-02-14
    • 2021-09-08
    • 1970-01-01
    • 2011-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多