Assembly.LoadAssembly, MEF и MAF: как они управляют различными сборками каркасов и как не блокировать загруженные сборки?
Я разрабатываю приложение с.NET, и это приложение должно быть в состоянии загрузить другой плагин (DLL). Приложение представляет собой простую форму, которая показывает выбранный плагин, а плагин UserControl со всеми необходимыми элементами управления для реализации функций.
Я подумываю разработать приложение и плагин для C#, но сначала для стандарта.NET Framework, а для второго - для WPF (и использовать элемент управления ElementHost в приложении для визуализации плагина в WPF).
Первый вопрос: таким образом, когда я загружаю плагин, разные сборки должны быть совместимы, верно?
Я попытался разработать эту систему тремя способами:
- используя класс Assembly и загружая вручную плагин.
- используя MEF
- используя MAF
Второй вопрос: в жизни системы может случиться так, что некоторые плагины создаются со старой версией WPF, а другие - с последней версией WPF. Какое лучшее решение среди перечисленных выше, чтобы гарантировать, что если, например, я загружаю плагин с более старой версией WPF после загрузки плагина с более новой версией WPF, приложение использует правильную версию WPF (более старая версия в примере)?
Кроме того, мне нужно реализовать систему для установки и удаления плагина во время выполнения. С 3) мне удалось это реализовать. С 1) и 2) я прочитал в Интернете, что единственный способ деинсталлировать плагин во время выполнения, это загрузить плагин сборки во вторичный домен приложений (с классом Assembly или с MEF), сделать сериализуемые классы плагина и при необходимости выгрузите AppDomain: выгрузите файл dll в mef
Однако с этой стратегией я столкнулся с проблемой: когда я использую инсанс сборки, загруженный во вторичный AppDomain (мне нужно вставить этот экземпляр в основную форму), основной AppDomain сериализует экземпляр и воссоздает его, но при этом, кроме того, чтобы утратить преимущества MEF, сборка остается заблокированной на главном домене приложений, и я не могу удалить плагин. Чтобы избежать этого, я должен установить ShadowCopyFiles = "true" в основном и дополнительном AppDomain, но у меня может возникнуть та же проблема при обновлении плагина, в котором будет обновленный dll, но с тем же именем (теневая копия все равно будет заблокирована).
Третий вопрос: есть ли другое решение для его реализации с 1) или 2)?
1 ответ
Что касается 3-го вопроса, только вчера, когда я провел один из последних тестов (найденных на разных форумах), возможно, я мог бы найти способ загрузить сборки в MEF, не блокируя файлы, не используя другой домен приложений (который в любом случае является громоздкой операцией).) и, следовательно, без использования ShadowCopy: идея состоит в том, чтобы прочитать dll и поместить содержимое в байтовый массив, создать AssemblyCatalog из этого массива, а затем добавить созданный AssemblyCatalog в каталог MEF:
CompositionContainer _container = null;
.
.
.
AggregateCatalog catalog = new AggregateCatalog();
.
.
.
String fileName = "pug-in1.dll"
.
.
.
Byte[] contFile = File.ReadAllBytes(fileName);
Assembly ass = Assembly.Load(contFile);
AssemblyCatalog assCat = new AssemblyCatalog(ass);
catalog.Catalogs.Add(assCat);
_container = new CompositionContainer(catalog)
try
{
_container.ComposeParts(this);
}
catch (CompositionException compositionException)
{
Console.WriteLine(compositionException.ToString());
}
.
.
.
Вроде работает и файлы не заблокированы