Страницы

Поиск по вопросам

вторник, 2 октября 2018 г.

Архитектура расширяемого приложения

Есть несколько C#-проектов (WindowsForms), и нужно их соединить в одно приложение.
Каждый из уже существующих проектов должен быть оформлен в виде плагина к этому новому приложению, назовем его PluginContainer. Разумеется, эти плагины ничего не должны знать друг о друге и никак не взаимодействуют. Главное приложение при запуске должно загрузить эти плагины в отдельных вкладках. Сам плагин должен состоять из файла представления, файла логики и xml-файла с описанием плагина.
Главная проблема - отсутствие опыта в проектировании таких систем и вообще опыта работы с ООП, не понимаю, с какого конца подойти. Смотрел в сторону MEF, прочитал несколько статей, но пока не могу оценить, насколько этот подход целесообразен.
Если без MEF, то, как я понял, в PluginContainer я должен описать несколько классов, которые обрабатывают плагины. Может, существует какой-то паттерн, который может мне помочь?
В общем, если кто-то имеет опыт в проектировании таких систем, то было бы очень интересно узнать, как это все грамотнее сделать.


Ответ

Приложение с плагинной архитектурой состоит из двух частей: хоста и собственно плагинов. В .NET хост обязательно должен содержать интерфейсную сборку, в которой объявлен интерфейс плагина. Плагин представляет собой сборку, снабжённую манифестом (манифест необязателен, но с ним будет быстрее работать), в которой находится класс, реализующий интерфейс, объявленный в интерфейсной сборке хоста. Манифест должен представлять собой файл с расширением, известным хосту, в котором записано имя сборки, которую требуется загрузить, и, если требуется, конкретные типы. При старте хост должен пройтись по директории, в которую предполагается помещать плагины, и открыть все файлы манифестов. После этого сборки, указанные в манифестах, загружаются вызовом Assembly.Load, Assembly.LoadFrom или Assenbly.LoadFile. При этом, если путь, по которому грузятся плагины, отличается от каталога приложения, этот путь надо добавить в список путей поиска сборок вызовом AppDomain.CurrentDomain.AppendPrivatePath. Затем для каждой сборки вызывается метод GetTypes() который возвращает список типов, объявленных в сборке. Каждый тип необходимо проверить на реализацию интерфейса плагина, вызвав typeof(IMyPlugin).IsAssignableFrom(current_type), и, если тип реализует интерфейс плагина, создать экземпляр интерфейса плагина вызовом Activator.CreateInstance. В результате формируется список экземпляров интерфейса, с которым что-то можно делать. В Вашем случае я бы порекомендовал в манифестах указывать файл представления (насколько я понимаю, Вы под представлением имеете в виду сборку с кодом представления), а в интерфейсе плагина сделать свойство, возвращающее контрол, который требуется отобразить на вкладке. Сборка с логикой должна помещаться рядом со сборкой с представлением и, по идее, должна загружаться автоматически при обращении к ней из сборки с пользовательским интерфейсом плагина.

Комментариев нет:

Отправить комментарий