Как использовать внешние плагины через конфигурационный файл (конфигурация времени выполнения) с Unity Container 5

Я пытаюсь настроить простой проект .NET Core 3.1, в котором используется Unity Container 5 https://github.com/unitycontainer/unity.

Я добавил ссылку на последний пакет Unity Configuration 5.11.1 (https://www.nuget.org/packages/Unity.Configuration/).

Затем я создал интерфейс, реализацию и тестовое приложение с простейшим конфигурационным файлом:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Unity.Configuration" />
  </configSections>
  <unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
    <container>
      <register
        type="Interfaces.InterfaceN, Interfaces"
        mapTo="Implementations.ImplementationN, Implementations">
      </register>
    </container>
  </unity>
</configuration>

Но я получаю System.InvalidOperationException:

{"Имя типа или псевдоним Реализации. РеализацияN, Реализации не могут быть разрешены. Пожалуйста, проверьте файл конфигурации и проверьте имя этого типа."}

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

P.S. Visual Studio 2019 16.4.4 Enterprise, Windows 10 1909 x64 Professional

PPS Тот же код, скомпилированный для .NET Framework 4.8, работает нормально — Гитхаб

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


person bairog    schedule 18.02.2020    source источник
comment
Несколько вопросов: IDE и версия? ОПЕРАЦИОННЫЕ СИСТЕМЫ?   -  person NotImplementedException    schedule 18.02.2020
comment
Visual Studio 2019 16.4.4 Корпоративная, Windows 10 1909 x64 Профессиональная   -  person bairog    schedule 18.02.2020


Ответы (1)


Я обнаружил, что это скорее проблема с загрузкой сборки .NET Core, чем проблема с контейнером IoC.

Короче говоря, если на сборку конкретно не ссылается ваше приложение, вам нужно сообщить загрузчику сборки .NET Core, где ее взять ДАЖЕ ЕСЛИ ОНА В ВАШЕЙ ПАПКЕ BIN.

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

Из репозитория примеров Autofac IoC:

// 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 container = new UnityContainer().LoadConfiguration();

var type = container.Resolve<InterfaceN>();

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

PS Еще немного информации из Майкрософт

person bairog    schedule 19.02.2020