2008-12-04 3 views
2

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

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

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

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

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

ответ

3

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

Решение, с которым я столкнулся, заключалось в использовании делегированного обработчика событий и его вызова с использованием BeginInvoke. Если вы не посмотрели на решение CodeProject: WCF/WPF Chat Application (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.

Смежные вопросы