Pull to refresh

Comments 43

Мне кажется, для большинства приложений это немного оверкилл.

Когда мы делали один проект с плагинами, то просто грузили все dll-ки из папки plugins и искали в них классы с нашим кастомным [MyPluginAttribute] и реализующие нужный интерфейс.
Естественно, всё было в пределах общего домена, на этом мы теряли безопасность и стабильность приложения, но из плюсов получали простоту реализации и дебага + скорость.
P.S.: перебор мы ограничивали только dll-ками в которых есть определённый PE-ресурс (не дотнетовский), и брали только assembly.GetExportedTypes.

Естественно, все метаданные о плагине можно сложить либо в кастомный атрибут либо в PE-ресурс (получается аналог манифеста).
это был reply первомы комментатору
Насколько я помню это было задолго до MEF. Второй дотнет только вышел тогда.
P.S.: ну и до MEF это явно не дотягивало, там был 1 файл на всё про всё, меньше 500 строк кода точно.
UFO just landed and posted this here
UFO just landed and posted this here
о! я нисколько не претендую на то, что предложенный мной подход самый удачный из возможных. Но в стоявшей когда-то задаче было необходимо показывать пользователю описание модуля, на основании которого он принимал решение о целесообразности использования модуля. Т.е. процесс загрузки сборки надо было оттянуть до последнего. Самым очевидным решение стало размещение описания в файле. Плюс использование файла дало еще некоторые преимущества (например возможность контроля целостности модуля).
вообще, было бы интересно почитать решения на основе Mono Cecil или даже MEF. Т.к. про первое слышу впервые, а второе появилось позже реализации описанной в статье идеи.
UFO just landed and posted this here
Хм, странное решение, есть аттрибуты и они гораздо лучше решают данную проблему.

Цепляем аттрибут к сборке и описываем.
Цепляем аттрибут к классам и метим их, я у себя мечу интерфейсом.

Потом все это легко используется, не требуется писать всякие левые xml файлы.

Так что советую разобраться с аттрибутами.
хм… очень может быть, что я чего-то не понимаю в работе с атрибутами, но на сколько мне известно, для получения атрибута класса необходимо произвести загрузку сборки в память. Плюс, возможно, что модуль требует наличие дополнительных библиотек, анализировать которые в поисках нужного атрибута, пустая трата времени.
Ну никто не запрещает создать кэш или еще чего.
кхм… грубо говоря «еще чего» я и предлагаю =)
Просто с атрибутами меньше возни, больше сокрыто и соответственно разработка модулей проще. В случае командной разработки думаю это важнее. Да и один раз подготовка, потом работает быстро.
Во всей статье ни слова про MEF, которая предназначена для решения как раз этих задач. Зачем опять изобретать велосипед?
когда было необходимо решить задачу модульности MEF еще не было (или я таки просто про нее не знал). Проект писался под Framework 3
Статью-то вы сейчас пишете. А сейчас показывать такой код и не сравнивать его с MEF как-то очень странно.
MEF умеет грузить модули только в тот же AppDomain.

Соответственно — как быть если плагины нужно уметь выгружать? Или нужно дать возможность сторонним разработчикам писать эти плагины?

Либо вот так вручную, либо использую MAF:
www.developerfusion.com/article/9396/creating-extensible-applications-with-maf/
«MEF умеет грузить модули только в тот же AppDomain.»
Это не совсем так. Под MEF — расширяемая архитектура. Из коробки он этого не умеет, но и только.

«как быть если плагины нужно уметь выгружать?»
Написать свой ExportProvider или Catalog (я, извините, точно уже не помню).

«Или нужно дать возможность сторонним разработчикам писать эти плагины?»
А это-то как связано?

Но речь-то даже не об этом, а о том, что статья о реализации плагинной архитектуры в .net без (хотя бы) слов «мы посмотрели на MEF, он вот так не умеет, поэтому сделали свое» выглядит странно.

PS Чего далеко ходить: pwlodek.blogspot.com/2011/07/isolating-mef-components.html
«Написать свой ExportProvider или Catalog (я, извините, точно уже не помню).»


Можно так. Но это автоматически обозначает что нужно разбираться во внутренностях довольно большого фреймворка. Тут уже нужно серьезно подумать, не проще ли написать легковесную плагинную систему под собственные требования, либо найти фрейворк который подходит под требования.

«А это-то как связано?»
Стабильность и безопасность. Чужому коду лучше жить в отдельном AppDomain.

«Статья о реализации плагинной архитектуры в .net без (хотя бы) слов «мы посмотрели на MEF, он вот так не умеет, поэтому сделали свое» выглядит странно.»

С этим согласен. Всегда сначала стоит искать готовые решения :)

«Чего далеко ходить: pwlodek.blogspot.com/2011/07/isolating-mef-components.html »

За ссылку спасибо. Но там автор сам говорит что это proof of concept, а не продакшн код. Коммуникация плагинов через WCF — это оверкилл :) Если бы на MEF была бы отлаженная реализация плагинов с изоляцией AppDomain, я бы с радостью воспользовался. Но сейчас вот на одном из проектов как-раз ситуация, что мы похоже откатываемся с MEF на самописный вариант (ну или может т.н. MAF).
«Но это автоматически обозначает что нужно разбираться во внутренностях довольно большого фреймворка.»
Не надо. Это стандартная точка расширения.

У меня есть мнение, что разобраться в ней несколько проще, чем написать свою систему плагинов. И уж тем более мне кажется, что если не хватает квалификации в ней разобраться, то лучше свой велосипед не изобретать.

«Стабильность и безопасность. Чужому коду лучше жить в отдельном AppDomain.»
Чужому коду лучше жить в другом процессе. А еще лучше — в чужом сервисе.

Все, очевидно, зависит от задач и ситуаций.

«Коммуникация плагинов через WCF — это оверкилл»
Зато надежно и очевидно.

«Но сейчас вот на одном из проектов как-раз ситуация, что мы похоже откатываемся с MEF на самописный вариант (ну или может т.н. MAF).»
Не очень понимаю, чем цельный самописный вариант надежнее MEF, расширенного самописным кодом. Ну, хозяин-барин, тут ничего больше не скажешь.
UFO just landed and posted this here
грубость ерунда. Профит важен. Буду признателен, если подробнее прокомментируете.
UFO just landed and posted this here
ясно. спасибо за замечание.
Очень странное решение.
А если модулю нужно взаимодействовать с каким-то там AppContext'ом? Как он получит к нему доступ?

Но, ведь всегда можно регистрировать типы в IoC и потом их резолвить.
И все модули в конструктор могут получать всё, что им там нужно. итд…

Тему можно развивать сколько угодно, но ваш пост можно описать проще: LoadInstance :)
задачи получения контекста приложения передо мной не вставало, поэтому указанную Вами проблему я решать даже не пытался. Увы.
Что же до IoC, то я не понимаю как они помогут решить проблему управления загрузкой сборок?
Вообще, Managed Extensibility Framework был доступен задолго до .NET 4.0, просто он не был в него включен. Сейчас в разработке MEF 2.0 с поддержкой дженериков и прочих вкусностей. Про создание модульных приложений хорошо написано здесь: Modular Application Development.
жаль, что мне попалась последняя статья раньше. За нее отдельное личное спасибо! Но в целом, на сколько я понял, идея о регистрации модулей в файле присутствует и там.
А как быть, если ВСЕ модули должны использовать общую библиотеку классов. Хранять рядом с каждым — точно не лучший вариант.

Не показано где же динамическое отключение (выгрузка) модуля.
Статья хороша комментариями, узнал про MEF и прочее. Сам сделал похожее решение, только имена классов отличались, прямо смешно как похоже получилось :). Только я кэш строил, а не манифесты.

Вобщем статья — собирательная. Спасибо.
> бинарные библиотеки плохо поддаются архивированию

Это не так. Дотнетовские бинарники ужимаются на 60-80% (в среднем приблизительно втрое).

> Его суть заключается в копировании файла библиотеки и загрузки в память уже ее копии, оригинал при этом остается доступен для удаления.

Assembly можно загрузить даже из byte[], копировать файл необязательно.

Ну и к рекомендации обратить внимание на MEF тоже стоит прислушаться.
UFO just landed and posted this here
Речь шла про Assembly.Load. И никаких велосипедов. :) Ну, это так, мелочь.
UFO just landed and posted this here
начитался в комментах про MEF и возникло несколько вопросов:
1. правильно ли я понимаю, что в MEF 1.0 нет возможности в рантайме подключать модули, которые неизвестны исполняемому коду? Типа рефлексии. Ну не могу я знать заранее, какие модули будут использоваться.

И второй вопрос, не про MEF:
2. Чтобы не грузить несколько одну и ту же библиотеку, можно ли написать поверх неё обёртку, подключать как обычный плагин. Сам же плагин будет работать на основе Синглтона. А раз домен приложения один, то и создавать несколько экземпляров, а от того и грузить одну и туже библиотеку не придется. В качестве примера COM-библиотеки Microsoft.Interopl.Office. Word, Excel…
1. Наоборот, все системы плагинов как раз и нацелены на ситуацию, когда к приложению подключаются произвольные модули, о которых оно в момент компиляции не знает. Приложению нужно знать лишь интерфейс подключения.

2. В одном AppDomain сборки (библиотеки) не дублируются. Одна сборка загружается только один раз.
Синглтон работает на другом уровне, не со сборками, а с классами (объектами). Это понятия из разных областей.
1. Так вот почитал я статью от уважаемого XaocCPS, там получается, что код, который импортирует модуль (подключает к себе), уже знает о существовании класса (не используется рефлексия), и обращается к нему именно по имени класса, а не интерфейса.

2. Я в курсе, что из разных. А что народ в тредах выше кипишит, что им придется зависимости одни и теже подтягивать, увелчивая расходы памяти
«Так вот почитал я статью от уважаемого XaocCPS, там получается, что код, который импортирует модуль (подключает к себе), уже знает о существовании класса (не используется рефлексия), и обращается к нему именно по имени класса, а не интерфейса.»
Это ошибка. MEF прекрасно грузит модули по интерфейсам и именам. Вы с typecatalog не путаете?
UFO just landed and posted this here
Sign up to leave a comment.

Articles