PRISM и WCF - Они хорошо играют?

Ok,

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

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

Моя идея теперь состоит в том, чтобы взять концепцию события из PRISM и расширить ее «по сети» с помощью WCF и обратных вызовов, как описано здесь Пример обратного вызова WCF AlarmClock.

Я создал небольшую картинку, чтобы проиллюстрировать идею (в основном для себя), возможно, это проясняет ситуацию: Иллюстрация  концепция

Серые стрелки означают «использование библиотеки». WCF-Event-Base означает обычные события PRISM, где метод публикации вызывается «по сети».

На ум приходят несколько вопросов:

  • Есть ли какие-нибудь известные примеры таких вещей?
  • Что будет лучшим способом «поднять» события по сети?
  • Любые возможные проблемы с этой концепцией (упомянутые ранее уродливые твари)

Что касается второго вопроса, в настоящее время я думаю о возбуждении событий с использованием строки (тип конкретного события, которое я хочу вызвать) и полезной нагрузки в качестве аргумента. Что-то вроде public void RaiseEvent(string eventType, object eventPayload){}. Полезная нагрузка должна быть сериализуемой, возможно, я даже включу хэш-проверку. (Это означает, что если я подниму, например, событие с изображением в качестве аргумента 10 раз, я передаю изображение только один раз, а затем использую хеш, чтобы сервер использовал буфер при публикации) ...

Хорошо, я думаю, вы уловили идею. Эта «штука» должна вести себя как одно гигантское приложение, используя своего рода WCF_EventAggregator вместо обычного PRISM IEventAggregato r. (вау, пока я писал, у меня возникла идея «просто» расширить IEventAggregator, надо подумать об этом) ...

Зачем я это пишу? Ну, в основном для обратной связи и для сортировки своих мыслей. Так что комментарии приветствуются, возможно, мне следует быть «осторожным»?

Крис

[РЕДАКТИРОВАТЬ]

Распределение клиентов

Количество клиентов должно быть неопределенным, сервер не должен знать клиентов. Сам сервер может быть клиентом для себя, вызывая строго типизированные события PRISM в других частях исходного кода.

Основное различие между «клиентом» и «сервером» - это фактическая реализация соединителя WCF_PRISM, см. Следующую главу ...

Поднятие клиентского события (функция PRISM)

В PRISM, чтобы вызывать простые события, вам даже НЕ нужна ссылка на интерфейс службы. IEventAggregator можно получить с помощью внедрения зависимостей, предоставив экземпляр желаемого события (например, WeatherChangedEvent). Это событие можно вызвать, просто вызвав eventInstance.Publish (23), потому что событие реализовано как public class WeatherChangedEvent : CompositePresentationEvent<int>

WCF - соединитель PRISM

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

Вот где должно произойти «волшебство». Клиенты будут включать в себя модуль призмы, отвечающий за подключение событий PRISM к «отправкам сообщений wcf». Он будет в основном подписываться на все доступные события в решении (все они в любом случае определены в модуле инфраструктуры) и отправлять сообщение WCF в случае возникновения события.

Разница между СЕРВЕРОМ и КЛИЕНТОМ заключается в реализации этого модуля. Должна быть небольшая разница по двум причинам.

  • Параметры настройки WCF
  • Поток событий для предотвращения бесконечного цикла

Поток событий будет (пример)

  1. Клиент получает ссылку на WeatherChangedEvent
  2. wChanged.Publish (27) -> обычное инициирование события PRISM
  3. Модуль WCF_PRISM подписан на событие и
  4. отправить это событие на сервер
  5. Сервер внутренне получает экземпляр WeatherChangedEvent и публикует
  6. Сервер перезванивает всем клиентам, вызывающим их WeatherChangedEvent

Открытые точки

Очевидный момент - предотвращение петли. Если сервер вызовет событие во ВСЕХ клиентах, клиенты обратятся к серверу, снова вызовут событие и так далее ... Таким образом, должна быть разница между событием, вызванным локально (что означает, что я должен отправить его на сервер) и «событие, вызванное сервером», что означает, что мне не нужно отправлять его на сервер.

Кроме того, если клиент сам инициировал событие, его не нужно вызывать сервером, потому что событие уже было инициировано (в самом клиенте, пункт 2).

Все это особое поведение будет инкапсулировано в модуле создания событий WCF, невидимым для остальной части приложения. Я должен подумать о том, «как узнать, что событие уже опубликовано», возможно, GUID или что-то в этом роде было бы хорошей идеей.

А теперь второй большой вопрос, что я имел в виду, когда раньше рассказывал о «струнах». Я не хочу писать новое определение интерфейса службы каждый раз, когда добавляю событие. Большинство событий в PRISM определяются одной строкой, особенно во время разработки я не хочу обновлять WCF_Event_Raising_Module каждый раз, когда добавляю событие.

Я думал об отправке событий напрямую при вызове WCF, например. используя функцию с подписью вроде:

public void RaiseEvent(EventBase e, object[] args)

Проблема в том, что я действительно не знаю, смогу ли я так просто сериализовать события PRISM. Все они являются производными от EventBase, но я должен это проверить ... По этой причине у меня возникла идея использовать тип (как строку), потому что я знаю, что сервер разделяет модуль инфраструктуры и может получить свой собственный экземпляр события (не нужно пересылать по сети, только аргумент)

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

Кстати. если кого-то совершенно сбивают с толку все эти разговоры о событиях, попробуйте PRISM. Вам понравится, даже если вы используете только DI и события (например, RegionManager не мой любимый)

Крис

[КОНЕЦ РЕДАКТИРОВАНИЯ 1]


person Christian Ruppert    schedule 20.10.2009    source источник
comment
+1 - интересный вопрос и хорошо продуманный вопрос.   -  person Russell    schedule 20.10.2009
comment
это будет приложение для одного клиента или для нескольких клиентов? Какую привязку планируете использовать (привязка-агностицизм - это сказка)   -  person Krzysztof Kozmic    schedule 20.10.2009
comment
Привязка будет nettcpbinding или wshttpdualbinding, поскольку мне нужна функция обратного вызова. Как управлять множеством клиентов будет интересным вопросом в ближайшем будущем ...   -  person Christian Ruppert    schedule 20.10.2009
comment
Составное событие призмы - это проблема пользовательского интерфейса, и его не следует сериализовать по сети. Самое большее, что вам нужно - сериализовать полезную нагрузку. Разделяйте свои проблемы ... не смешивайте WCF и Prism.   -  person Anderson Imes    schedule 20.10.2009
comment
Хорошо, но я не думаю, что это просто проблема пользовательского интерфейса. Я думаю, что события PRISM больше похожи на события .NET на стероидах. Тем не менее, сериализация их, скорее всего, не лучшая идея.   -  person Christian Ruppert    schedule 21.10.2009


Ответы (2)


Это очень интересный подход. Я бы сказал здесь только две вещи:

  1. У вас действительно возникают проблемы, если вы используете строки и параметры объекта. Здесь можно использовать строго типизированные события EventAggregator (унаследованные от CompositeEvent). Если вы это сделаете, ремонтопригодность значительно вырастет.
  2. Ваша модель для вашего WCF -> EventAggregator должна рассматривать все, к EventAggregator и от него, как к «событию», а все к / от сервисов WCF как к «сообщениям». На самом деле вам следует учитывать то, что вы, по сути, переводите событие EventAggregator в сообщение, а не задаете вопрос «как вызвать события WCF».

Я думаю, что то, что вы делаете, возможно. Глядя на вашу реализацию, мне действительно нравится, как вы думаете об этом.


Незначительная альтернатива (со строгой типизацией)

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

Рассматривали ли вы возможность реализации интерфейса службы на основе EventAggregator? Допустим, в вашем примере у вас есть служба WCF IWeatherService, с которой вы работаете. В настоящее время, насколько я понимаю, ваше использование будет выглядеть примерно так:

  1. Клиент использует клиентскую библиотеку событий WCF и вызывает RaiseEvent («ChangeWeather», Weather.Sunny);
  2. Клиентская библиотека событий WCF преобразует это в соответствующий вызов службы WCF, ожидающей получения этого сообщения, используя для этого интерфейс канала IWeatherService. Вероятно, с большим неприятным оператором switch, основанным на имени вызова метода.

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

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

public ClientWeatherService : IWeatherService
{

    IEventAggregator _aggregator;
    public ClientWeatherService(IEventAggregator aggregator) 
    { 
        _aggregator = aggregator; 
    }

    public void ChangeWeather(Weather weather)
    {
        ChangeWeatherEvent cwEvent = _aggregator.GetEvent<ChangeWeatherEvent>();
        cwEvent.Publish(weather);
    }
}

Оттуда, вместо того, чтобы напрямую использовать вашу «клиентскую библиотеку событий WCF», они напрямую используют IWeatherService, не зная, что он не вызывает фактическую службу.

public MyWeatherViewModel : ViewModel
{
    IWeatherService _weatherService;
    public MyWeatherViewModel(IWeatherService weatherService)
    {
        _weatherService = weatherService;
    }
}

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

Просто мысль.

Мне очень нравятся такие вопросы. Я бы хотел, чтобы больше людей задавали подобные вопросы в Stackoverflow. Заставляет мозг двигаться по утрам :)

person Anderson Imes    schedule 20.10.2009
comment
Спасибо за ваш отзыв. Да, я думаю, что ваш подход лучше, или, скажем так, вы лучше сформулировали то, что я собирался делать в любом случае. Я буду редактировать свой первоначальный пост с вашими обновлениями. Возвращайтесь через 30 минут :-) - person Christian Ruppert; 20.10.2009
comment
Привет! Рад, что смог помочь. Было интересно думать об этом. Очень жду, что вы придумали. - person Anderson Imes; 20.10.2009
comment
Хорошо, редактирование выполнено ... Да, если я посмотрю на это, я думаю, что даже создам для этого кодовый комплекс. Я имею в виду модуль WCF Event для PRISM, определенно приятная вещь. И мне всегда очень нравятся такие проекты, в которых не нужно начинать с нуля (Toolkit, WPF contrib, Clog) - person Christian Ruppert; 20.10.2009
comment
Тебе удалось это сделать? Кодпроект? Мне любопытен результат. - person husayt; 12.02.2010

Вроде сложный подход к проблеме.

Вы вызываете событие из клиентского приложения или вызываете события из службы с помощью контракта обратного вызова? или оба?

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

Все, что вам действительно нужно, это класс, который абстрагирует детали службы wcf от клиента и предоставляет его интерфейс через события Prism.

Я лично не хотел бы изменять / расширять компонент инфраструктуры и создавать зависимость от конкретной службы wcf.

person Andronicus    schedule 20.10.2009