Как: Отзывчивая доступная Wcf дуплексная связь - PullRequest
2 голосов
/ 04 декабря 2008

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

Мастер-сервис отправляет уведомления подписанным клиентам, когда суб-сервисы изменяются (добавляются, удаляются и т. Д.) Также подуслуги отправляют уведомления каждые несколько секунд.

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

Решение, которое я придумал, заключается в использовании http-привязки (чтобы немедленно узнать, когда отправка не удалась) и создание явных служб обратного вызова на клиенте, но для этого мне нужно написать много уродливого кода инфраструктуры.

Итак, мой вопрос: есть ли лучший способ сделать это с WCF. Наиболее привлекательным вариантом были Callback Contracts, потому что это освобождает меня от необходимости управлять службой обратного вызова вручную, если только он не может ждать подтверждения от одного клиента перед попыткой отправки следующему.

1 Ответ

3 голосов
/ 04 декабря 2008

У меня похожая среда (без динамических сервисов), и у меня возникла очень похожая проблема при сбое клиентских каналов. Первое решение, которое я придумал, заключалось в том, чтобы обернуть обратные вызовы в операторах try / catch и удалить нарушающий работу клиент, если что-то пошло не так, но это имело проблемы и не выглядело так, как будто оно вообще масштабировалось.

Решение, которое я в итоге выбрал, состояло в том, чтобы использовать делегированный обработчик событий и вызывать его с помощью BeginInvoke. Если вы еще не посмотрели на решение CodeProject: приложение для чата WCF / WPF (Chatters) , я рекомендую проверить его.

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

public bool Login() 
{
    ...
    _myEventHandler = new ChatEventHandler(MyEventHandler);
    ChatEvent += _myEventHandler;
    ...
}

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

private void BroadcastMessage(ChatEventArgs e)
{
    ChatEventHandler temp = ChatEvent;
    if (temp != null)
    {
        foreach (ChatEventHandler handler in temp.GetInvocationList())
        {
            handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);
        }
    }
}

Когда возвращаются результаты, результат обрабатывается, и если что-то плохое происходит, обработчик событий для этого канала удаляется:

private void EndAsync(IAsyncResult ar)
{
    ChatEventHandler d = null;
    try
    {
        //get the standard System.Runtime.Remoting.Messaging.AsyncResult,and then
        //cast it to the correct delegate type, and do an end invoke
        System.Runtime.Remoting.Messaging.AsyncResult asres = (System.Runtime.Remoting.Messaging.AsyncResult)ar;
        d = ((ChatEventHandler)asres.AsyncDelegate);
        d.EndInvoke(ar);
    }
    catch(Exception ex)
    {
        ChatEvent -= d;
    }
}

Приведенный выше код изменен (немного) из приложения для чата WCF / WPF, опубликованного Sacha Barber .

...