Как использовать внешние плагины через конфигурационный файл (конфигурация времени выполнения) с Autofa c 5 - PullRequest
0 голосов
/ 19 февраля 2020

Я пытаюсь настроить простой . NET Core 3.1 проект, который использует Autofa c 5 Io C Контейнер .

Я добавил ссылку на последнюю Autofa c .Configuration 5.0.0 package .

Я создал интерфейс, реализацию и тестовое приложение с простой JSON конфигурацией (следуя этому руководству ):

{
  "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 :

Тип «Реализации. РеализацияN, Реализации» не найден. Может потребоваться квалификация сборки, например, «MyType, MyAssembly»

Я загрузил свой код в GitHub . Любая помощь приветствуется.

PS Visual Studio 2019 16.4.5 Enterprise, Windows 10 1909 x64 Professional

ОБНОВЛЕНИЕ: Чтобы уточнить больше - моя конечная цель - иметь Interfaces.dll без специальных ссылок, Implementations.dll со ссылкой ТОЛЬКО Interfaces.dll и Test.exe со ссылкой ТОЛЬКО Interfaces.dll (и, конечно, пакет Autofa c). Я ожидаю, что Autofa c загрузит указанный класс c из указанной сборки c (которая указана в config. json) через Reflection. Это было возможно с Unity Container , и я ожидал добиться того же с Autofa c Io C.

Еще раз: Мне нужен подход без ЛЮБОГО проекта, ссылающегося на Implementations.dll, я должен быть в состоянии изменить конкретную c реализацию (через изменение config. json) без перекомпиляции.

Ответы [ 2 ]

2 голосов
/ 19 февраля 2020

Я обнаружил, что это скорее проблема ". NET Загрузка сборки ядра", чем проблема Autofa c.

Короче говоря, если сборка специально не упоминается По вашему приложению вам нужно указать. NET Загрузчик сборки ядра, где его взять ДАЖЕ, ЕСЛИ ЭТО В ВАШЕМ ПАКЕТЕ БИН .

Так что если вы (как и я) не хотите чтобы иметь bootstrap библиотеку, которая ссылается на все библиотеки реализации, которые вам нужны, но вы хотите иметь конфигурацию времени выполнения через конфигурационный файл - вы должны сделать следующее.

С Autofa c примеров :

// 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();

работает как шарм.

PS Дополнительная информация от Microsoft

0 голосов
/ 19 февраля 2020

Проблема в том, что основной проект ищет тип, который вы ввели в файл конфигурации. json, но у него нет ссылки на проект реализации, поэтому он не найдет модуль. Мое решение состоит в том, чтобы сначала добавить ссылку на проект реализации, а затем создать модуль autofa c в проекте реализаций (вам нужен autofa c lib в проекте реализаций, поэтому лучше иметь общее ядро ​​или просто общий проект для все проекты):

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

Вся ваша регистрация проекта имплиментации происходит здесь. Затем измените файл конфигурации. json следующим образом:

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

Тогда все должно быть в порядке.
Если вы не хотите, чтобы ваш основной проект имел ссылку на проект реализации, вам нужно добавить какой-то новый проект для регистрации всех модулей вашего приложения. И в нем должны быть ссылки на все проекты.

...