ПРИЗМ и WCF - Они играют хорошо?

Хорошо,

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

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

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

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

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

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

  • Существуют ли какие-либо существующие примеры для таких вещей?
  • Каким будет лучший способ "поднять" события по проводке?
  • Любые возможные проблемы с этим понятием (уродливые твари, упомянутые ранее)

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

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

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

Крис

[редактирует]

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

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

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

Повышение клиентских событий (функция PRISM)

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

Разъем WCF - PRISM

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

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

Разница между SERVER и CLIENT заключается в реализации этого модуля. Должно быть небольшое различие из-за двух вещей.

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

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

  • Клиент получает ссылку на WeatherChangedEvent
  • wChanged.Publish(27) → нормальное событие PRISM
  • Модуль WCF_PRISM подписывается на событие и
  • отправить это событие на сервер
  • Сервер внутри получает экземпляр WeatherChangedEvent и публикует
  • Сервер обращается ко всем клиентам, повышающим их WeatherChangedEvent

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

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

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

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

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

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

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

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

Пока я здесь, я буду держать вопрос открытым для получения дополнительной информации. Главное новое "понимание", которое я только что получил: подумайте о проблеме рекурсии /infite loop.

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

Крис

[END EDIT 1]

Ответы

Ответ 1

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

  • Вы действительно задаете проблемы, если используете строки и параметры объекта. Здесь можно найти сильные события EventAggregator (наследующие от CompositeEvent). Ремонтопригодность будет идти вверх, если вы это сделаете.
  • Ваша модель для вашего WCF → EventAggregator должна учитывать все в EventAggregator и из EventAggregator как "событие" и все в/из служб WCF как "сообщения" . То, что вы действительно должны учитывать, заключается в том, что вы по существу переводите событие EventAggregator в сообщение, вместо того, чтобы задавать вопрос "как я могу создавать события WCF".

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


Незначительная альтернатива (с сильным вводом текста)

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

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

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

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

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

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. Убирает мозг утром:)

Ответ 2

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

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

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

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

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