Managed And-In Framework

53

В версии .NET 4 реализованы две технологии для создания и использования дополнений - MEF и MAF. Во время выполнения приложения, использующие МЕF, могут находить дополнения в каталоге или в сборке и подключать их, используя атрибуты. Отличие от MAF состоит с том, что MEF не предлагает отделения дополнения от размещаемого приложения с помощью доменов приложений или других процессов. И здесь вступает в действие МАF Платой за достижение упомянутого разделения в МАF будет дополнительная сложность. Чтобы воспользоваться преимуществами обеих технологий — МЕF и MAF, — их можно комбинировать. Разумеется, это также привнесет сложность.

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

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

Обнаружение

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

Активация

С динамическими загружаемыми сборками невозможно просто использовать операцию new для создания экземпляра. Такие сборки можно создавать с помощью класса Activator. Также различные опции активизации могут применяться, если дополнение загружено внутри другого домена приложений или нового процесса.

Изоляция

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

Жизненный цикл

Очистка объектов — работа для сборщика мусора. Однако сборщик мусора здесь не поможет, поскольку дополнения могут быть активизированы в другом домене приложений или в другом процессе. Другой способ удержания объекта в памяти — счетчик ссылок или механизм аренды и спонсирования.

Поддержка версий

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

Теперь давайте рассмотрим архитектуру MAF, и то, как платформа решает перечисленные проблемы. При проектировании платформы MAF преследовались следующие цели:

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

Конвейеры

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

На рисунке показан конвейер, лежащий в основе архитектуры МАF. В центре находится сборка контракта. Эта сборка содержит интерфейс контракта, перечисляющий методы и свойства, которые должны быть реализованы дополнением и могут быть вызваны хостом. Левая часть контракта — это сторона хоста, а правая — сторона дополнения:

Конвейер MAF

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

Размещаемое приложение ссылается на представление хоста; дополнение ссылается на представление дополнения. Сами представления содержат абстрактные классы представлений, которые определяют методы и свойства, как они определены контрактом.

Класс хоста имеет ассоциацию с абстрактным представлением хоста и вызывает его методы. Абстрактный класс представления реализован адаптером хоста. Адаптеры осуществляют соединение между представлением и контрактом. Адаптер дополнения реализует методы и свойства контракта. Этот адаптер содержит ссылку на представление дополнения и переадресует вызовы со стороны хоста к представлению дополнения.

Класс адаптера хоста определяет конкретный класс, унаследованный от абстрактного базового класса представления хоста, реализуя его методы и свойства. Этот адаптер включает ссылку на контракт для переадресации вызовов от представления к контракту.

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

Обнаружение

Каким образом размещаемое приложение может находить новые дополнения? Архитектура MAF использует предопределенную структуру каталогов для нахождения дополнений и других сборок конвейера. Компоненты конвейера должны располагаться в следующих каталогах:

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

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

Кэшированная информация о компонентах конвейера создается вызовами методов класса AddInStore. Метод Update() находит новую сборку, которая еще не указана в списке хранилища. Метод Rebuild() перестраивает полностью двоичный файл хранилища с информацией о дополнениях. Ниже перечислены методы класса AddInStore:

Rebuild(), RebuildAddIns()

Метод Rebuild() перестраивает кэш со всеми компонентами конвейера. Если дополнение хранится в другом каталоге, то метод RebuildAddIns() может быть использован для перестройки кэша дополнений.

Update(), UpdateAddIns()

В то время как метод Rebuild() перестраивает целиком кэш конвейера, метод Update() просто обновляет кэш информацией о новых компонентах конвейера. Метод UpdateAddIns() обновляет только кэш дополнений.

FindAddIn(), FindAddIns()

Эти методы используются для нахождения дополнений с использованием кэша. Метод FindAddIns() возвращает коллекцию всех дополнений, которые соответствуют представлению хоста. Метод FindAddIns() возвращает определенное дополнение.

Активизация и изоляция

Метод FindAddIns() класса AddInstore возвращает коллекцию объектов AddInToken, представляющую дополнение. Через класс AddInToken можно получить доступ к информации о сборке, такой как имя, описание, издатель и версия. Вы можете активизировать дополнения методом Activate().Ниже перечислены свойства и методы класса AddInToken:

Name, Publisher, Version, Description

Свойства Name, Publisher, Version И Description класса AddInToken возвращают информацию о дополнении, которая назначается дополнению с помощью атрибута AddinAttribute.

AssemblyName

AssemblyName возвращает имя сборки, содержащей дополнение.

EnableDirectConnect

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

QualificationData

Дополнение может пометить домен приложения и требования безопасности атрибутом QualificationDataAttribute. Дополнение может перечислять требования к безопасности и изоляции. Например, [QualificationData ("Isolation","NewAppDomain")] означает, что дополнение должно быть размещено в новом процессе. Можно прочитать эту информацию из AddInToken для активизации дополнения со специфицированными требованиями. Вдобавок к требованиям домена приложений и безопасности, этот атрибут можно использовать для передачи специальной информации по конвейеру.

Можно также указать полномочия, которые получит дополнение.

Одно дополнение может разрушить все приложение. Вам наверняка приходилось видеть, как терпит крах Internet Explorer из-за сбоя дополнения. В зависимости от типа приложения и типа дополнения этого можно избежать, позволив дополнению работать в другом домене приложений или внутри другого процесса. Новый домен приложения может также иметь ограниченные полномочия.

Метод Activate() класса AddInToken имеет несколько перегрузок, которым можно передавать среду, куда должно загружаться дополнение. Допустимые варианты перечислены в таблице:

AppDomain Можно передать новый домен приложения, в который должно быть загружено дополнение. Подобным образом его можно сделать независимым от размещаемого приложения и, кроме того, оно может быть затем выгружено этим доменом приложения.
AddInSecurityLevel Если дополнение должно быть запущено с другими уровнями безопасности, можно передать значение перечисления AddInSecurityLevel. Возможные значения — Internet, Intranet, FullTrust и Host.
PermissionSet Если предопределенные уровни безопасности недостаточно специфичны, можно также присвоить PermissionSet домену приложения дополнения.
AddInProcess Дополнение также может быть запущено внутри другого процесса размещаемого приложения. Методу Activate() необходимо передать новый процесс AddInProcess. Новый процесс может завершаться, когда все дополнения выгружены, или продолжать выполнение. Это устанавливается с помощью свойства KeepAlive.
AddInEnvironment Передача объекта AddInEnvironment — еще один вариант определения домена приложения, куда должно быть загружено приложение. Конструктору AddInEnvironment можно передать объект AppDomain. Можно также получить существующий AddInEnvironment дополнения из свойства AddInEnvironment класса AddInController.
Пройди тесты
Лучший чат для C# программистов