MEF: «Невозможно загрузить один или несколько запрошенных типов. Получите исключения LoaderException для получения дополнительной информации» - PullRequest
19 голосов
/ 26 октября 2010

Сценарий: я использую Managed Extensibility Framework для загрузки плагинов (экспорт) во время выполнения на основе контракта интерфейса, определенного в отдельной DLL.В моем решении Visual Studio у меня есть 3 различных проекта: хост-приложение, библиотека классов (определяющая интерфейс - «IPlugin») и другая библиотека классов, реализующая интерфейс (экспорт - «MyPlugin.dll»).

Хост ищет экспорт в своем собственном корневом каталоге, поэтому во время тестирования я собираю все решение и копирую Plugin.dll из папки bin / release библиотеки классов Plugin в каталог отладки хоста, чтобы его нашел каталог DirectoryCatalog ииметь возможность добавить его в CompositionContainer.Plugin.dll не копируется автоматически после каждой перестройки, поэтому я делаю это вручную каждый раз, когда вносю изменения в контракт / реализацию.

Однако пару раз я запускал хост-приложение, не имеяСначала скопировал (обновленный) Plugin.dll, и во время композиции возникла исключительная ситуация:

Unable to load one or more of the requested types. Retrieve the LoaderExceptions for more information

Это, конечно, из-за того, что Plugin.dll пытаетсяимпорт из реализует другую версию IPlugin, где сигнатуры свойств / методов не совпадают.Хотя этого легко избежать в контролируемой и контролируемой среде, просто избегая (скучно) устаревших реализаций IPlugin в папке плагинов, я не могу полагаться на такие предположения в производственной среде, где могут встречаться устаревшие плагины.

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

Есть ли способ сделать это?Я думаю, один из нескольких возможных вариантов:

  • Существует флаг для CompositionContainer («игнорировать неудачные импорты») до или при вызове Compose
  • Существуетаналогичный флаг, который указывается для атрибута <ImportMany()>
  • . Существует способ "привязать" к процессу итерации, лежащему в основе Compose (), и иметь возможность обрабатывать каждый (неудачный) импорт по отдельности
  • Использование строгой подписи для того, чтобы как-то только искать импорт, реализующий текущую версию IPlugin

Идеи?

Ответы [ 3 ]

15 голосов
/ 26 октября 2010

Я также столкнулся с аналогичной проблемой .

Если вы уверены, что хотите игнорировать такие "плохие" сборки, то решение - вызвать AssemblyCatalog.Parts.ToArray () сразу после создания каждого каталога сборки.Это вызовет ReflectionTypeLoadException, который вы упомянули.Затем у вас есть возможность перехватить исключение и игнорировать неверную сборку.

Когда вы создали AssemblyCatalog объектов для всех "хороших" сборок, вы можете объединить их в AggregateCatalog и передать ихконструктор CompositionContainer.

8 голосов
/ 02 декабря 2011

Эта проблема может быть вызвана несколькими факторами (любые исключения в загруженных сборках), как говорит исключение, взгляните на ExceptionLoader, чтобы (надеюсь) получить некоторое представление

Другая проблема / решение, которое я нашел,это при использовании DirectoryCatalog , если вы не укажете второй параметр "searchPattern", MEF загрузит ВСЕ библиотеки в этой папке (включая сторонние) и начнет искать экспорттипы, которые также могут вызвать эту проблему, решение состоит в том, чтобы иметь имя соглашения на всех сборках, которые экспортируют типы, и указать, что в конструкторе DirectoryCatalog я использую * _Plugin.dll, таким образом, MEF будет загружать только сборки, которые содержат экспортированныеТипы

В моем случае MEF загружал DLL-файл NHibernate и выдавал какую-то ошибку версии сборки в LoaderException (эта ошибка может происходить с любой из DLL в каталоге), этот подход решил проблему

7 голосов
/ 17 октября 2012

Вот пример вышеупомянутых методов:

var di = new DirectoryInfo(Server.MapPath("../../bin/"));

        if (!di.Exists) throw new Exception("Folder not exists: " + di.FullName);

        var dlls = di.GetFileSystemInfos("*.dll");
        AggregateCatalog agc = new AggregateCatalog(); 

        foreach (var fi in dlls)
        {
            try
            {
                var ac = new AssemblyCatalog(Assembly.LoadFile(fi.FullName));
                var parts = ac.Parts.ToArray(); // throws ReflectionTypeLoadException 
                agc.Catalogs.Add(ac);
            }
            catch (ReflectionTypeLoadException ex)
            {
                Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
            }
        }

        CompositionContainer cc = new CompositionContainer(agc);

        _providers = cc.GetExports<IDataExchangeProvider>();
...