Короткая версия
У меня есть приложение, которое использует инфраструктуру плагинов. Плагины имеют настраиваемые свойства, которые помогают им знать, как выполнять свою работу. Плагины сгруппированы в профили, чтобы определить, как выполнить задачу, а профили хранятся в файлах XML, сериализованных DataContractSerializer. Проблема заключается в том, что при чтении файлов конфигурации десериализация приложения должна знать обо всех подключаемых модулях, определенных в файле конфигурации. Я ищу способ справиться с разрешением неизвестных плагинов. См. Раздел предлагаемого решения ниже для нескольких идей, которые я рассмотрел в реализации, но я открыт практически для всего (хотя я бы предпочел не изобретать приложение заново).
Detail
Фон
Я разработал своего рода Систему автоматизации бизнес-процессов для внутреннего использования в компании, в которой я сейчас работаю, в C # 4. Она полностью использует «плагины» для определения всего ( от задач, которые должны быть выполнены, до определения единиц работы) и в значительной степени опирается на модель динамической конфигурации, которая в свою очередь опирается на динамические объекты C # 4 / DLR для выполнения заданий. Это немного тяжело при выполнении из-за его динамического характера, но оно работает последовательно и работает достаточно хорошо для наших нужд.
Он включает пользовательский интерфейс конфигурации WinForms, который широко использует Reflection для определения настраиваемых свойств / полей плагинов, а также свойств / полей, которые определяют каждую единицу работы, подлежащую обработке. Пользовательский интерфейс также построен на основе движка BPA, поэтому он имеет полное представление о (свободной) объектной модели, которая позволяет движку выполнять свою работу, что, по совпадению, привело к нескольким улучшениям пользовательского интерфейса, таким как выполнение специальных заданий и проверка времени ввода пользовательских данных. Опять же, есть возможности для совершенствования, однако, похоже, он делает свою работу.
Пользовательский интерфейс конфигурации использует DataContractSerializer для сериализации / десериализации указанных параметров, поэтому любые подключаемые модули, на которые ссылается конфигурация, должны быть загружены до (или во время) загрузки конфигурации.
Структура
Механизм BPA реализован в виде общей сборки (DLL), на которую ссылаются служба BPA (служба Windows), пользовательский интерфейс конфигурации (приложение WinForms) и тестер плагинов (версия консольного приложения службы Windows). ). Каждое из трех приложений, которые ссылаются на общую сборку, содержит только минимальный объем кода, необходимый для выполнения их конкретной цели. Кроме того, все плагины должны ссылаться на очень тонкую сборку, которая в основном просто определяет интерфейс (ы), который должен реализовывать плагин.
Проблема
Из-за модели расширяемости, используемой в приложении, всегда существовало требование, чтобы пользовательский интерфейс конфигурации запускался из того же каталога (на том же ПК), что и приложение-служба. Таким образом, пользовательский интерфейс всегда знает обо всех сборках, о которых знает Служба, поэтому их можно десериализовать, не сталкиваясь с отсутствующими сборками. Теперь, когда мы приближаемся к развертыванию системы, наши сетевые администраторы в целях безопасности обратились с просьбой разрешить удаленный интерфейс конфигурации на любом ПК в нашей сети. Как правило, это не было бы проблемой, если бы всегда был известный набор сборок для развертывания, однако, с возможностью расширения приложения с помощью сборок, созданных пользователем, должен быть способ разрешения сборок, из которых подключаемые модули может быть создан / использован.
Предлагаемое (потенциально очевидное) решение
Добавьте службу WCF в приложение-службу, чтобы разрешить типичные операции CRUD для конфигураций, о которых знает этот экземпляр службы, и переработать пользовательский интерфейс конфигурации, чтобы он действовал больше как SSMS с моделью Connect / Disconnect.Это на самом деле не решает проблему, поэтому нам также нужно было бы представить какой-то ServiceContract из приложения-службы, чтобы разрешить запрашивать сборки, о которых он знает / имеет доступ.Это нормально и довольно просто, однако возникает вопрос: «Когда пользовательский интерфейс должен узнать о сборках, о которых Служба знает?»При подключении мы могли бы отправлять все сборки из Сервиса в пользовательский интерфейс, чтобы гарантировать, что он всегда знает обо всех сборках, которые делает сервис, но это мешает управлению AppDomain (возможно, излишне) и конфликтам версий сборок.Поэтому я предложил подключиться к событиям AppDomain.AssemblyResolve / AppDomain.TypeResolve, чтобы загружать только сборки, о которых клиент пока не знает, и только по мере необходимости.Это не обязательно устраняет проблемы управления AppDomain, но определенно помогает решить конфликты версий и связанные с этим проблемы.
Вопрос
Если вы застряли со мной так долгоЯ аплодирую и благодарю вас, но теперь я, наконец, подхожу к актуальному вопросу здесь.После нескольких месяцев исследований и, наконец, приходя к выводу, мне интересно, сталкивался ли кто-нибудь здесь с подобной проблемой, и как вы справились с ошибками и недостатками?Есть ли стандартный способ справиться с этим, который я полностью пропустил, или у вас есть какие-либо рекомендации, основанные на том, как вы видели это успешно обработанным в прошлом?Видите ли вы какие-либо проблемы с предлагаемыми подходами или можете предложить альтернативу?
Я знаю, что не все живут в моей голове, поэтому, пожалуйста, дайте мне знать, если вам нужны дополнительные разъяснения / объяснения.Спасибо!
Обновление
Я слегка встряхнул MEF и чувствую, что это слишком упрощенно для моих целей.Дело не в том, что его нельзя было согнуть, чтобы удовлетворить требования плагинов для моего приложения, проблема в том, что это будет слишком громоздким и грязным, чтобы сделать его возможным.Это хорошее предложение, и у него есть большой потенциал, но в его нынешнем состоянии его просто еще нет.
Есть другие идеи или отзывы о моих предложенных решениях?
Обновление
Я не знаю, является ли проблема, с которой я сталкиваюсь, слишком локализованной, если я не смог правильно описать то, что я пытаюсь достичь, или этот вопрос слишком неоправданно длинныйбыть прочитанным полностью;но те немногие ответы, которые я получил, оказались достаточно полезными, чтобы помочь мне по-другому осмыслить проблему и выявить некоторые недостатки в том, к чему я стремлюсь.
Короче, я пытаюсь сделать триприложения, которые в своем текущем состоянии обмениваются информацией (конфигурация / сборки), используя общую структуру каталогов, и пытаются заставить эти приложения работать в сети с минимальным влиянием на удобство использования и архитектуру.
Общий доступ к файлам кажется очевидным ответом на эту проблему (как @SimonMourier предложил в комментариях), но их использование приводит к отсутствию контроля и отладки , когда что-то идет не так.Я вижу их как жизнеспособное краткосрочное решение, но в долгосрочной перспективе они просто кажутся неосуществимыми.