MEF Explorer – поиск ошибок

DevBookmark_Mef_ Платформа MEF (link eng/rus) является каркасом системы Ultima Businessware®. Она собирает приложение из независимых компонентов, в качестве которых выступают ядерные службы, скрипты и прикладные классы. MEF используется и в серверной, и в клиентской частях, благодаря чему программа в обоих случаях имеет одинаковую модульную структуру и использует единый API, хорошо документированный и достаточно популярный.

MEF представляет собой систему позднего связывания компонентов, основанную на правилах сопоставления. Сопоставление происходит между так называемыми импортами и экспортами, предоставляемыми компонентами. Чтобы некоторый компонент заработал, всем его импортам должны быть сопоставлены экспорты других компонентов. Связывание происходит во время выполнения программы, что обеспечивает необходимую гибкость. Компоненты, из которых собирается программа, могут разрабатываться параллельно разными командами программистов: скажем, форма клиентского приложения может использовать серверную службу, которая находится в процессе разработки, при условии, что интерфейс этой службы уже формально описан.

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

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

The composition produced a single composition error. The root cause is provided below. Review the CompositionException. Errors property for more detailed information.

 

1) No exports were found that match the constraint:

ContractName          Ultima.Scripting.IUserCommand

RequiredTypeIdentity  Ultima.Scripting.IUserCommand

RequiredMetadata

   ScriptID          (Ultima.Scripting.IScriptMetadata)

 

Resulting in: Cannot set import '

   ContractName            Ultima.Scripting.IUserCommand

   RequiredTypeIdentity    Ultima.Scripting.IUserCommand

   RequiredMetadata

       ScriptID            (Ultima.Scripting.IScriptMetadata)' on part '(name)'

 

Element:

   ContractName            Ultima.Scripting.IUserCommand

   RequiredTypeIdentity    Ultima.Scripting.IUserCommand

   RequiredMetadata

       ScriptID            (Ultima.Scripting.IScriptMetadata) --> Unknown Origin

 

  at System.ComponentModel.Composition.CompositionResult.ThrowOnErrors(AtomicComposition atomicComposition)

  at System.ComponentModel.Composition.Hosting.ImportEngine.SatisfyImportsOnce(ComposablePart part)

  at System.ComponentModel.Composition.Hosting.CompositionContainer.SatisfyImportsOnce(ComposablePart part)

Из текста ошибки понятно только, что какой-то компонент не может быть предоставлен по требованию системы. Какой именно компонент вызвал ошибку и как эту ошибку исправлять – не ясно.

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

ошибка в каком-нибудь скрипте (не обязательно том, который запрашивался);

ошибка в какой-нибудь клиентской форме (или одной из ее зависимостей).

Для разбора подобных ошибок на основе консольной утилиты Mefx был разработан инструмент MEF Explorer. Он показывает структуру каталогов MEF клиентской и серверной частей (на соответствующих закладках).

MEFexplorer

MEFexplorer1

Если ошибок нет, все импорты компонентов сопоставлены экспортам каких-нибудь других компонентов, и у всех компонуемых частей отображается статус Scripts_scr_DictEditForm1_CheckTick_ Accepted.

Больший интерес, разумеется, представляют другие статусы. Любая ошибка связывания означает, что компонент был отвергнут по одной из причин:

Scripts_scr_DictEditForm1_CheckCross_

Primary Rejection – отсутствие для некоторых импортов компонента соответствующих экспортов;

Scripts_scr_DictEditForm1_CheckExclamation_

Rejected – экспорты компонента присутствуют, но не могут быть созданы из-за того, что для их импортов, в свою очередь, отсутствуют необходимые экспорты.

Рассмотрим действия прикладного разработчика при возникновении ошибки.

Предположим, ошибка связывания (No exports were found that match the constraint...) происходит при запросе MobileStorePickupService. Настоящая проблема, однако, заключена не в нем. Если открыть скрипт в редакторе, можно убедиться, что он компилируется без ошибок. Для поиска причины следует запустить MEF Explorer и поискать в списке Composable parts по статусу Rejected или Primary Rejection и по имени компонент, вызвавший ошибку.

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

MEFexplorer2

В приведенном примере видно, что проблема заключается IStoreZonePickupService. Эта прикладная служба отсутствует в каталоге на стороне сервера. Возможны такие причины ее отсутствия:

для службы создали интерфейс, но еще не написали реализацию;

реализация есть, но имеет ошибки компиляции;

MEF Cache у скрипта службы по какой-то причине пуст (возможно, в результате слияния версий метаданных).

Для исправления обнаруженной ошибки необходимо:

найти интерфейс IStoreZonePickupService в справочнике Interfaces:

MEFexplorer3

проверить, есть ли реализация для этого интерфейса (если нет, добавить):

MEFexplorer4

если реализация есть, следует исправить ее скрипт:

MEFexplorer5