Использование абстрактного класса в качестве контракта в рамках плагина - PullRequest
1 голос
/ 25 февраля 2010

Может ли абстрактный класс использоваться в качестве объекта контракта между 'Host' и 'plugin'? Идея заключается в том, что плагин наследует контракт (мы называем его адаптером). Мы также понимаем, что все участники в рамках должны наследовать MarshalByRefObject (MBRO). Итак, это то, что мы думали -

Хост

class Host : MarshalByRefObject
{
}

Договор :

public abstract class PluginAdapter : MarshalByRefObject
{
}

Plugin

class myPlugin : PluginAdapter
{
}

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

{
    ObjectHandle instHandle = Activator.CreateInstance(
    newDomain, data.Assembly.FullName, data.EntryPoint.FullName);

    PluginAdapter adapter = (PluginAdapter)instHandle.Unwrap();
}

РЕДАКТИРОВАТЬ : где data - тип бетона myPlugin.

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

EDIT : В этом примере Ричард Блеветт - C # Reflection - он использует гораздо более простую реализацию:

Договор

public interface IPlugIn  
{  
    // do stuff  
}

Plugin

public class PlugIn : MarshalByRefObject, IPlugIn  
{  
}

Теперь, если в качестве контракта используется абстрактный класс, плагин не может наследовать как контракт, так и MBRO. Что тогда станет лучшей реализацией для масштабируемой инфраструктуры плагинов. Должны ли мы пойти дальше и внедрить удаленное взаимодействие, хотя изначально мы разрабатываем для работы на одной машине? Ожидается, что этот проект будет распространяться по сети, возможно, через Интернет. Мы просто еще не внедрили Tcp, потому что пытаемся полностью понять основы инфраструктуры плагинов.

Имеет ли смысл реализовать удаленное взаимодействие Tcp на одном компьютере с использованием обратной связи?

Ответы [ 4 ]

6 голосов
/ 25 февраля 2010

Абстрактные классы - лучший выбор для этого, imho. В первую очередь потому, что интерфейсы сложнее для версии. В этом сообщении в блоге описывается проблема, которая может возникнуть у вас в будущем, если вы не используете базовые классы. Это правило относится не только к плагинам, кстати.

О вашем дизайне ...

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

Например, если плагин возвращает IEnumerable для одного из своих методов, он может вернуть реализацию IEnumerable, определенную в сборке плагина. Если это не расширяет MBRO, основной домен приложения должен будет загрузить сборку плагина.


Я загрузил три проекта, связанных с доменами приложений, здесь:

http://cid -f8be9de57b85cc35.skydrive.live.com / self.aspx / Public / NET% 20AppDomain% 20Tests / appdomaintests.zip

Один использует обратные вызовы через домены приложений, второй - обработка событий между доменами, а третий - пример плагина.

В примере плагина приложение определяет интерфейс плагина (это демо, а не лучшие практики!) И хост плагина. Приложение загружает сборку плагина с диска и передает его в домен приложения плагина через прокси хоста плагина, где он загружается. Затем хост плагина создает экземпляр плагина и использует его. Но когда хост возвращает тип, определенный в сборке плагина, обратно в домен приложения, сборка плагина загружается в основной домен приложения, что делает бессмысленным весь плагин.

Лучше всего избежать этого - предоставить абстрактный базовый класс для плагинов, который не помечен как сериализуемый и не расширяет MBRO, и возвращать только примитивы или запечатанные типы, которые вы определили, обратно через границу из домена плагина.

ПРИМЕЧАНИЕ: все проекты 4.0 RC. Вам нужно это или выше, чтобы запустить их. В противном случае вам придется отредактировать файлы проекта вручную или пересобрать их, чтобы запустить их в b2 или 2008.

2 голосов
/ 25 февраля 2010

При условии, что data.EntryPoint.FullName - это полное имя типа, приведенный выше код должен работать.

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

1 голос
/ 26 февраля 2010

Возможно, вы захотите взглянуть на MAF (Managed Addin Framework) , которая является платформой расширяемости, встроенной в .NET для выполнения надстроек. Он похож (и старше), чем MEF (Managed Extensibility Framework) , но имеет больше возможностей для хранения плагинов в собственном домене приложения, среди прочего.

0 голосов
/ 25 февраля 2010

Если data.EntryPoint.FullName относится к конкретному типу myPlugin, я не вижу причин, по которым это не сработает (если только не возникают проблемы с загрузкой сборки в другом домене приложения, но это другая проблема).

...