Вопрос о том, как реализовать c# хост-приложение с подобной плагину архитектурой

Я хочу иметь приложение, которое работает Хостом многих других небольших приложений. Каждое из тех приложений должно работать видом плагина к этому главному приложению. Я называю их плагинами не в смысле, они добавляют что-то к главному приложению, но потому что они могут только работать с этим Хост-приложением, поскольку они зависят от некоторых его сервисов.

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

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

Что лучшее (.NET) подход к этому виду ситуации? Заставьте их всех работать на том же AppDomain, но каждом в различном Потоке? Использовать другой AppDomains? Один для каждого "плагина"? Как я заставил бы их общаться с Хост-приложением? Какой-либо другой способ сделать это?

Хотя скорость не является проблемой здесь, я не хотел бы за вызовы функции быть, что намного медленнее, чем они - когда мы работаем только с обычным приложением.NET.

Спасибо

Править: Возможно, я действительно должен использовать другой AppDomains. Из того, что я читал, загрузка блоков в другом AppDomains является единственным способом позже смочь разгрузить их от процесса.

6
задан devoured elysium 23 April 2010 в 01:49
поделиться

3 ответа

Я реализовал кое-что в этом направлении, используя Managed Addin Framework (MAF) в пространстве имен System.Addin. С помощью MAF вы упаковываете свои надстройки как отдельные библиотеки DLL, которые ваше хост-приложение может обнаруживать и запускать в своем домене приложения, в отдельном домене для всех надстроек или каждой надстройке в своем собственном домене. С помощью теневого копирования и отдельных доменов вы даже можете обновить надстройку, не закрывая хост-приложение.

Ваше хост-приложение и надстройки взаимодействуют через контракты, которые вы получаете из интерфейсов MAF. Вы можете отправлять объекты туда и обратно между хостом и надстройками. Cotnracts обеспечивают интерфейс черного ящика между надстройками и хостом, позволяя вам изменять реализацию надстройки без ведома хоста.

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

Для моего приложения надстройка использует простые классы супервизора, которые запускают рабочие классы в своих собственных потоках, которые выполняют всю обработку. Рабочие перехватывают свои собственные исключения, которые они возвращают своему руководителю с помощью методов обратного вызова. Супервизоры могут перезапускать работников или предпринимать другие действия.Хост управляет супервизорами через командный контракт, который инструктирует их запускать и останавливать исполнителей и возвращать данные.

Мое хост-приложение - это служба Windows. Рабочие потоки вызвали исключения по всем обычным причинам (включая ошибки!), Но хост-приложение никогда не аварийно завершало работу ни в одной из наших установок. Поскольку службы отладки неудобны, надстройки позволяют мне создавать тестовые приложения, использующие одни и те же контракты, с дополнительной гарантией того, что я тестирую то, что развертываю.

Надстройки также могут отображать элементы пользовательского интерфейса. Это очень полезно для меня, так как мне нужно развернуть приложение контроллера со службой хоста, поскольку у служб нет пользовательского интерфейса. Каждый плагин включает в себя собственный интерфейс контроллера. Само приложение контроллера очень простое - оно загружает надстройки и отображает их элементы пользовательского интерфейса. Это позволяет мне поставлять обновленную надстройку с обновленным интерфейсом и не нужно поставлять новый контроллер.

Хотя контроллер и хост-сервис используют одни и те же надстройки, они не наступают друг на друга; на самом деле они даже не знают, что другое приложение использует те же надстройки. Контроллер и хост общаются друг с другом через общую базу данных, но вы также можете использовать другой механизм взаимодействия приложений, например MSMQ. В следующей версии хостом будет служба WCF с надстройками на бэкэнде и веб-службами для управления.

Это немного многословно, но я хотел дать вам представление о том, насколько универсален MAF. Это не так сложно, как может показаться на первый взгляд, и с его помощью вы можете создавать надежные приложения.

5
ответ дан 16 December 2019 в 21:36
поделиться

Это интересный вопрос.

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

Моей второй мыслью было разработать сервис-ориентированную платформу. Хост-приложение будет своего рода «вещателем плагинов», который будет публиковать ваши плагины в ServiceHost в другом потоке. Поскольку это должно быть действительно отзывчивым и «не требующим особой настройки», хост-приложение может взаимодействовать с плагином через канал именованных каналов (NetNamedPipesBinding для WCF), что означает, что он взаимодействует только с локальными каналами и не требует какой-либо сетевой конфигурации или знаний вообще. . Думаю, это может быть хорошим решением твоей проблемы.

С уважением.

1
ответ дан 16 December 2019 в 21:36
поделиться

Это зависит от того, насколько вы хотите доверять расширениям. Я работаю над похожим приложением и предпочел в основном доверять коду расширения, так как это значительно упрощает работу. Я вызываю код из общего потока (в моем случае расширения на самом деле не `` запускаются '' в каком-либо непрерывном цикле, а скорее выполняют определенные задачи, которые хочет выполнить основное приложение) и перехватывают исключения в этом потоке, чтобы чтобы предоставить полезные предупреждения о том, что загруженные расширения работают некорректно.

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


Что касается разгрузки, да, вы можете выгрузить код и метаданные для сборки, только если вы поместите их в AppDomain. Тем не менее, если вы не хотите часто загружать и выгружать программу в течение всего срока службы, накладные расходы, связанные с хранением кода в памяти, не обязательно являются проблемой. Любые фактические экземпляры или ресурсы, использующие типы из сборки, будут по-прежнему очищены сборщиком мусора, когда вы перестанете «использовать» его, поэтому тот факт, что он все еще находится в памяти, не означает утечки памяти.

Если ваш основной вариант использования - это серия подключаемых модулей, которые вы обнаруживаете один раз при запуске, а затем предоставляете возможность создания экземпляра во время работы вашего приложения, я предлагаю изучить реальный объем памяти, связанный с загрузкой всех из них при запуске, и держать их загруженными. Если вы используете AppDomains, там также будут дополнительные накладные расходы (например, память для прокси-объектов и загруженный / JIT-код для поддержки маршалинга AppDomain). Также будут накладные расходы ЦП, связанные с маршалингом и сопутствующей сериализацией.

Короче говоря, я бы использовал AppDomain только в том случае, если бы выполнялось одно из следующих условий:

  • Я хочу получить настоящую изоляцию в целях безопасности кода (т.е.Мне нужно запускать ненадежный код изолированно)

  • Мое приложение критически важно, и мне абсолютно необходимо убедиться, что в случае сбоя подключаемого модуля он не сможет остановить мое основное приложение.

  • Мне нужно многократно загружать и выгружать один и тот же плагин, чтобы поддерживать динамические изменения в DLL. В основном это происходит, если мое приложение не может перестать работать, но я хочу исправлять плагины, пока они еще работают.

Я бы не предпочел AppDomains с единственной целью уменьшить возможное использование памяти за счет разрешения Unload.

2
ответ дан 16 December 2019 в 21:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: