Я разделил свою проблему на короткую и длинную версию для людей, у которых мало времени.
Краткая версия:
Мне нужна архитектура для системы с плагинами поставщиков и потребителей. Поставщики должны внедрять межсетевой IProvider, и потребители должны внедрить IConsumer. Исполнительному приложению следует знать только IProvider и IConsumer. Потребительская реализация может запросить исполняющую сборку (с помощью ServiceProcessor), которые провайдеры реализуют InterfaceX и получают список обратно. Эти объекты IProvider должны быть переданы в InterfaceX (у потребителя), чтобы иметь возможность подключить пользователя к некоторым событиям, которые определяет InterfaceX. Это не удастся, потому что исполняющая сборка каким-то образом не знает этого типа InterfaceX (сбой при отказе). Решение заключалось бы в том, чтобы включить InterfaceX в некоторую сборку, которая включает как плагины, так и исполняемую ссылку на сборку, но это должно означать перекомпиляцию для каждой новой пары поставщиков/потребителей и крайне нежелательно.
Любые предложения?
Длинная версия:
Я разрабатываю некий общий сервис, который будет использовать плагины для достижения более высокого уровня повторного использования. Услуга состоит из какой-либо реализации шаблона Observer с использованием Провайдеров и Потребителей. Как поставщики, так и потребители должны быть плагинами для основного приложения. Позвольте мне сначала объяснить, как работает сервис, перечисляя проекты, которые у меня есть в моем решении.
Проект A: проект службы Windows для размещения всех плагинов и основных функций. Проект TestGUI Windows Forms используется для упрощения отладки. Экземпляр класса ServiceProcessor из Project B выполняет связанные с плагинами вещи. Вложенные папки "Потребители" и "Поставщики" этого проекта содержат вложенные папки, в которых каждая подпапка содержит соответственно пользовательский или провайдер-плагин.
Проект B: библиотека классов, содержащая класс ServiceProcessor (который выполняет загрузку и отправку плагинов между плагинами и т.д.), IConsumer и IProvider.
Проект C: библиотека классов, связанная с проектом B, состоящая из TestConsumer (реализация IConsumer) и TestProvider (реализация IProvider). Дополнительный интерфейс (ITest, сам полученный из IProvider) реализуется TestProvider.
Цель состоит в том, что плагин Consumer может запросить ServiceProcessor, у которого есть Провайдеры (реализующие хотя бы IProvider)). Возвращенные объекты IProvider должны быть отправлены на другой интерфейс, который он реализует (ITest) в реализации IConsumer, чтобы потребитель мог привязать обработчики событий к событиям ITest.
Когда запускается проект A, загружаются подпапки, содержащие плагины потребителя и поставщика. Ниже приведены некоторые проблемы, с которыми я столкнулся до сих пор, и попытался решить.
Интерфейс ITest использовался для реализации в Project C, поскольку это относится только к методам и событиям, которые знают TestProvider и TestConsumer. Общая идея состоит в том, чтобы сохранить простой проект и не знать, что делают плагины друг с другом.
С ITest в проекте C есть и код в методе Initialize TestConsumer, который передает IProvider в ITest (это не может не произойти в одной библиотеке классов, когда объект, реализующий ITest, известен как объект IConsumer), неверное литье возникла ошибка. Эта ошибка может быть решена путем размещения интерфейса ITest в проекте B, на который ссылается также проект A. Это очень нежелательно, поскольку нам нужно перекомпилировать проект A при создании нового интерфейса.
Я пытался помещать ITest в единую библиотеку классов, на которую ссылается только проект C, поскольку только провайдер и потребитель должны знать об этом интерфейсе, но безуспешно: при загрузке плагина в CLR указано, что указанный проект не может быть найденным. Это можно решить, подключившись к событию AssemblyResolve текущего AppDomain, но так или иначе это кажется нежелательным. ITest снова вернулся к проекту B.
Я попытался разделить проект C на отдельный проект для потребителя и поставщика, и оба загружают сборки, которые сами работают хорошо: обе сборки находятся в коллекции Assemblies или в текущем AppDomain: Сборка найдена: Datamex.Projects.Polaris.Testing.Providers, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = 2813de212e2efcd3 Сборка найдена: Datamex.Projects.Polaris.Testing.Consumers, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = ea5901de8cdcb258
Поскольку потребитель использует Поставщика, ссылка была сделана от Потребителя к Поставщику. Теперь событие AssemblyResolve возобновилось, указав, что ему нужен следующий файл: AssemblyName = Datamex.Projects.Polaris.Testing.Providers, Version = 1.0.0.0, Culture = neutral, PublicKeyToken = 2813de212e2efcd3
Мои вопросы: Почему это? Этот файл уже загружен правильно? Почему бросок от IProvider к некоторому интерфейсу, который я знаю, он реализует невозможно? Вероятно, это связано с тем, что сама исполняющая программа не знает этого интерфейса, но не может ли это быть загружено динамически?
Моя конечная цель: Потребительские плагины запрашивают у ServiceProcessor, какие у него есть Поставщики, которые реализуют интерфейс x. Поставщики могут быть отправлены на этот интерфейс x, не выполняя сборку, которая знает интерфейс x.
Кто-нибудь, кто может помочь?
Спасибо заранее, Erik