如何使用 Autofac 5 通过配置文件(运行时配置)使用外部插件
Howto use external plugins via config file (runtime configuration) with Autofac 5
我正在尝试设置一个简单的 .NET Core 3.1 项目,该项目使用 Autofac 5 IoC Container.
我添加了对最新 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:
The type 'Implementations.ImplementationN, Implementations'
could not be found. It may require assembly qualification,
e.g. "MyType, MyAssembly"
我已将我的代码上传到 GitHub。感谢任何帮助。
P.S. Visual Studio 2019 16.4.5 企业版,Windows 10 1909 x64 专业版
更新: 澄清更多 - 我的最终目标是 Interfaces.dll 没有特殊参考,Implementations.dll 仅参考 Interfaces.dll 和 Test.exe 参考只有 Interfaces.dll(当然还有 Autofac 包)。我希望 Autofac 通过反射从特定程序集(在 config.json 中指定)加载特定 class。这可以通过 Unity Container 实现,我希望通过 Autofac IoC.
实现同样的效果
再一次:我需要一个没有任何项目引用Implementations.dll的upproach,我应该能够改变具体的实现(通过改变config.json)没有重新编译。
问题是主项目正在查找您在 config.json 文件中输入的类型,但它没有对实现项目的引用,因此它不会找到模块。我的解决方案是,首先添加对实施项目的引用,然后在实施项目中创建一个 autofac 模块(实施项目中需要 autofac 库,因此最好为所有项目共享内核或简单地共享项目):
public class ImplementationModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ImplementationN>().As<InterfaceN>();
}
}
您所有的实施项目注册都在这里。
然后像这样更改 config.json 文件:
{
"modules": [
{
"type": "Implementations.ImplementationModule, Implementations"
}
]
}
那应该就没问题了。
如果您不想让您的主项目引用实施项目,您需要将一些新项目添加到应用程序所有模块的注册中。它也应该有对所有项目的引用。
我发现这更像是一个“.NET Core 程序集加载”问题,而不是 Autofac 问题。
长话短说,如果程序集没有被您的应用程序专门引用,您需要告诉 .NET Core 程序集加载程序从哪里获取它即使它在您的 BIN 文件夹中.
因此,如果您(像我一样)不想拥有引用您需要的 所有 实现库的 bootstrap 库,但您想要运行时配置通过配置文件 - 您应该执行以下操作。
// 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.
//
//
// 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
的更多信息
我正在尝试设置一个简单的 .NET Core 3.1 项目,该项目使用 Autofac 5 IoC Container.
我添加了对最新 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:
The type 'Implementations.ImplementationN, Implementations' could not be found. It may require assembly qualification, e.g. "MyType, MyAssembly"
我已将我的代码上传到 GitHub。感谢任何帮助。
P.S. Visual Studio 2019 16.4.5 企业版,Windows 10 1909 x64 专业版
更新: 澄清更多 - 我的最终目标是 Interfaces.dll 没有特殊参考,Implementations.dll 仅参考 Interfaces.dll 和 Test.exe 参考只有 Interfaces.dll(当然还有 Autofac 包)。我希望 Autofac 通过反射从特定程序集(在 config.json 中指定)加载特定 class。这可以通过 Unity Container 实现,我希望通过 Autofac IoC.
实现同样的效果再一次:我需要一个没有任何项目引用Implementations.dll的upproach,我应该能够改变具体的实现(通过改变config.json)没有重新编译。
问题是主项目正在查找您在 config.json 文件中输入的类型,但它没有对实现项目的引用,因此它不会找到模块。我的解决方案是,首先添加对实施项目的引用,然后在实施项目中创建一个 autofac 模块(实施项目中需要 autofac 库,因此最好为所有项目共享内核或简单地共享项目):
public class ImplementationModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<ImplementationN>().As<InterfaceN>();
}
}
您所有的实施项目注册都在这里。 然后像这样更改 config.json 文件:
{
"modules": [
{
"type": "Implementations.ImplementationModule, Implementations"
}
]
}
那应该就没问题了。
如果您不想让您的主项目引用实施项目,您需要将一些新项目添加到应用程序所有模块的注册中。它也应该有对所有项目的引用。
我发现这更像是一个“.NET Core 程序集加载”问题,而不是 Autofac 问题。
长话短说,如果程序集没有被您的应用程序专门引用,您需要告诉 .NET Core 程序集加载程序从哪里获取它即使它在您的 BIN 文件夹中.
因此,如果您(像我一样)不想拥有引用您需要的 所有 实现库的 bootstrap 库,但您想要运行时配置通过配置文件 - 您应该执行以下操作。
// 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.
//
//
// 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
的更多信息