вторник, 27 января 2009 г.

Much of muchness. Part 6. XAppDomain EventBroker.

Алилуйя! Мы добрались до заключительной (и самой интересной) части.
Здесь я расскажу, свой подход к реализации кросс-доменного EventAgregator'а.

Необходимость создания этого монстра диктует плагинная архитектура - различные изолированные модули, ничего не знающие об остальных плагинах, должны уметь оповещать окружающих о каком-то важном событии, причем получатели сообщения, обязательно будут жить в другом, изолированном домене.
Фундаментом моей платформы является CAB - composite application block, содержащим реализацию EventAggregator'а. Как сделать так, чтобы он не был ограничен одним доменом? Никак. Дело в том, что в CAB композиты публикуют события и подписываются на них при помощи ObjectBuilder pipeline, в котором специальная стратегия EventAggregator'а аккумулирует всю эту информацию. В нашем же случае все объекты плагинов будут создаваться MAF pipeline'ом, и доступа к ним у нас не будет. Так как же быть? Использовать WCF - Windows Communication Foundation.

В WCF из коробки нет реализации механизма Publish-Subscribe, но есть все средства для его реализации. Подходов может быть несколько:

За основу решения я взял последний framework от Juval Lowy и расширил его, сделав его contract&topic based, с тем, чтобы интегрировать его с CAB EventAggregator (topic based). Но обо всем по порядку.

Publish-Subscribe framework (С) Juval Lowy IDesign.

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

Прежде всего небольшим изменениям подвергся контракт сервиса подписки. Теперь ему передается не имя метода, которое надо вызвать у подписчика, а некий объект, выражающий интерес в подписке, который содержит имя метода (contract based) и имя topic (topic based), по которым EventAggregator сможет определить заинтересованность того или иного подписчика в неком событии.





Интерфейс сервиса подписки кросс-доменного EventAggregator'а для моей платформы выглядит следующим образом:

основное его назначение - сообщать WCF инфраструктуре о том, что IEventNotifyCallback - это callback contract для нашего кросс-доменного EventAggregator'а. DomainDTO - это суперкласс для моих DTO.

Сам сервис реализован в классе XAppDomainEventBrokerSubscription.

Он выполняет функции сервиса подписки и связывает инфраструктуру CAB с нашим механизмом. Последнее осуществляется аналогичным CAB'овскому образом - поиск публикаторов событий (по соответствующим аттрибутам) и аккумуляция этих публикаторов в CAB EventAggregator с одной лишь разницой, что вместо подписчика подставляется суррогатный объект, который при получении события опубликует его в нашей кросс-доменной системе (фактически просто пробросит дальше). Интегрируется этот сервис в CAB при помощи специальной стратегии ObjectBuilder'а XAppDomainEventBrokerStrategy.


Публикацией ведает XAppDomainEventBrokerPublication - наследник слегка измененного PublicationService сервиса из framework'а Juval Lowy. Первый реализует callback контракт как контракт сервиса, а последний на основании вызываемого метода и topic находит и вызывает соответствующий метод у соответствующего подписчика.


Но возникает резонный вопрос - а где, собственно, этому сервису передается topic? И куда его вообще воткнуть, если это contract-based framework? Ответ прост. Засунуть в заголовок
сообщения и занимаются этим клиенты сервиса. Их только надо унаследовать от PublisherServiceClient - часть моей инфраструктуры WCF (может быть опишу попозже).


Обратите внимание - у базового клиента сервиса подписки есть свойство EventTopic, с помощью которого мы можем передать это значение в WCF pipeline через расширение канала EventTopicChannelExtension, с одним единственным свойством - EventTopic.
Помните суррогатные объекты, добавлявшиеся в EventBroker CAB? Так вот они публикуют события через EventPublisherClient, передавая ему значение EventTopic из аттрибута.
Как EventTopicChannelExtension попал в канал? Все тот же базовый клиент при создании фабрики каналов добавляет EventTopicFlowBehavior, выполняющий всю работу.




Собственно всю работу делает даже не он, а следующие два джентельмена:



Первый, как следует из его названия, инициаллизирует канал, добавляя в него уже упоминавшееся выше расширение EventTopicChannelExtension для передачи EventTopic второму джентельмену, который собственно добавляет этот topic в заголовок передаваемого сообщения.
Из этого самого заголовка, слегка модифицированный мной, PublicationService вычленяет EventTopic и фильтрует по нему подписчиков.

Вот и все! Теперь все, что нужно сделать по шагам:
1. Создать прокси к сервису подписки и подписаться на интересуемое событие, указав при желании метод контракта, который следует вызвать.
2. Создать прокси к сервису публикации и вызвать, мимикрирующий под контракт подписчика сервис публикации, передав при желании topic.

Не очень надеюсь вы не запутались, потому что сам запутывался не раз.

P.S. ссылки на предыдущие посты в этой серии
Удачи!