Я пытаюсь сделать приложение на основе плагинов в C #. Прямо сейчас плагины используют MEF для обнаружения. У меня проблема с различными версиями общих библиотек, используемых хост-приложением и плагином.
На высоком уровне я хочу n + 1 каталогов, один для хоста, n для плагинов, со всеми файлами, которые нужны плагинам или хосту внутри их собственных папок.
У меня есть два решения: одно - MEF Interface, Shared Library и Plugin Host. Второй - это интерфейс MEF, общая библиотека и реализация плагинов.
Это упрощенное представление моей проблемы, демонстрирующее поведение:
Если я изменяю сигнатуру функции ShowMessage в проекте Shared Library, а затем перестраиваю только решение «Реализация плагина», я получаю исключение при вызове PrintInfo. Мне нужен способ, чтобы на хосте плагинов была загружена одна версия, а в реализации плагинов могла быть вторая.
MEF Interface Project
using System.ComponentModel.Composition;
namespace TestProject
{
[InheritedExport(typeof(IPlugin))]
public interface IPlugin
{
string Name { get; }
void PrintInfo();
}
}
Общая библиотека
using System.Windows.Forms;
namespace TestProject
{
public class SharedLibrary
{
#if true
public static void ShowMessage(string message)
{
MessageBox.Show(message);
}
#else
public static void ShowMessage(string[] message)
{
string msg = String.Join("\n", message);
MessageBox.Show(msg);
}
#endif
}
}
Плагин Host
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.ComponentModel.Composition.Hosting;
using System.Reflection;
using System.Windows.Forms;
namespace TestProject
{
public partial class Form1 : Form
{
[ImportMany(typeof(IPlugin), AllowRecomposition = true)]
List<IPlugin> allPlugins { get; set; }
SharedLibrary sl = new SharedLibrary();
public Form1()
{
InitializeComponent();
AggregateCatalog catalog = new AggregateCatalog();
DirectoryCatalog pluginDir = new DirectoryCatalog(@"..\..\..\Plugin\bin\Debug");
catalog.Catalogs.Add(pluginDir);
CompositionContainer container = new CompositionContainer(catalog);
container.ComposeParts(this);
}
private void button1_Click(object sender, EventArgs e)
{
string ver = Assembly.GetAssembly(sl.GetType()).GetName().Version.ToString();
MessageBox.Show("Presenter version = " + ver);
foreach (var plugin in allPlugins)
{
SharedLibrary.ShowMessage("Starting Plugin: " + plugin.Name);
// this explodes when the shared library in the plugin directory doesn't match
plugin.PrintInfo();
}
}
}
}
Реализация плагина
using System.Reflection;
using System.Windows.Forms;
namespace TestProject
{
public class Plugin : IPlugin
{
public string Name { get; } = "Test Plugin";
SharedLibrary sl = new SharedLibrary();
public void PrintInfo()
{
string ver = Assembly.GetAssembly(sl.GetType()).GetName().Version.ToString();
MessageBox.Show("Plugin version = " + ver);
#if true
SharedLibrary.ShowMessage("I am a plugin" + "\n" + Assembly.GetExecutingAssembly().GetName().Version.ToString());
#else
SharedLibrary.ShowMessage(new string[] { "I am a plugin", Assembly.GetExecutingAssembly().GetName().Version.ToString() });
#endif
}
}
}