Использование абстрактного класса в качестве контракта в платформе плагина

StackOverflow https://stackoverflow.com/questions/2336265

Вопрос

Можно ли использовать абстрактный класс в качестве объекта контракта между «Хостом» и «плагином»?Идея в том, что плагин наследует контракт (мы называем его адаптером).Мы также понимаем, что все участники структуры должны унаследовать MarshalByRefObject (МБРО).Итак, вот о чем мы подумали -

Хозяин:

class Host : MarshalByRefObject
{
}

Договор:

public abstract class PluginAdapter : MarshalByRefObject
{
}

Плагин:

class myPlugin : PluginAdapter
{
}

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

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

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

РЕДАКТИРОВАТЬ:где data это конкретный тип myPlugin.

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

РЕДАКТИРОВАТЬ:В этом примере Ричарда Блюетта - С# отражение - он использует гораздо более простую реализацию:

Договор:

public interface IPlugIn  
{  
    // do stuff  
}

Плагин:

public class PlugIn : MarshalByRefObject, IPlugIn  
{  
}

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

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

Это было полезно?

Решение

Имхо, абстрактные классы — лучший выбор для этого.Это прежде всего потому, что интерфейсы сложнее версионировать. Этот пост в блоге описывает проблему, с которой вы можете столкнуться в будущем, если не будете использовать базовые классы.Кстати, это правило применимо не только к плагинам.

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

Плагины не должны расширять 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.

Другие советы

Если «data.EntryPoint.FullName» является полным именем типа, приведенный выше код должен работать.

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

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top