2009-09-04 1 views
0

Сегодня у меня есть вопрос WCF, хотя он, вероятно, относится и к другим сетевым моделям в .NET.WCF: DuplexSessionChannel, асинхронные операции и исключение

У меня есть служба WCF, которая предоставляет операцию Send (Message) OperationContract, которая является OneWay = true. Теперь эта служба имеет канал обратного вызова для возврата сообщений клиенту.

В любом случае, я пытаюсь (успешно) вызвать этот метод отправки от моего клиента асинхронно. В DuplexSessionChannel я вызываю BeginSend (Message, OnSendComplete, null), и у меня есть метод OnSendComplete (IAsyncResult), который вызывает EndSend (asyncResult) в DuplexSessionChannel.

Услуга имеет CallbackContract и использует тот же шаблон BeginSend()/EndSend() для отправки обратно клиенту, который вызывается на канале callBack, который я получаю с помощью OperationContext.Current.GetCallbackChannel.

Клиент на своем DuplexSessionChannel вызывает BeginReceive()/EndReceive() при приеме сообщений обратно из канала обратного вызова служб.

Несмотря на то, что все работает, я не понимаю, что на самом деле делают методы <Operation>(), и это то, что мне нужно объяснить.

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

Я не эксперт WCF, но не сдерживаю детали, мне нужны знания. Я видел такие типы Begin/End перед другими асинхронными операциями во время моей карьеры, но никогда не понимал, что происходит.

Заранее спасибо.

ответ

1

Похоже, что ваш вопрос - это только начало/конец APM (асинхронная модель программирования). Вкратце, APM принимает метод синхронизации как

R Foo(A a); // R is some result type, A is some argument type 

и разбивает его на асинхронные методы BeginFoo и EndFoo. Основное преимущество возникает, когда операция выполняет действительно асинхронную работу системы (например, разговаривает с сетью), которая может быть долговременной (по крайней мере, по сравнению с другими функциями, например, общение с сетью может занимать сотни миллисекунд или более). Этот шаблон дает вам возможность сообщить системе о начале операции, а затем перезвонить вам, когда результат операции будет готов. Преимущество шаблона заключается в том, что вам не нужно блокировать управляемый поток во время ожидания этого вызова (что означает, например, что вы можете иметь тысячи ожидающих чтения/записи в сети без необходимости в тысячах потоков, ура, потоки дороги).

Итак, «BeginFoo» - это то, как вы говорите «запустите метод с этими аргументами», а затем, когда вы получите обратный вызов (как уведомление о том, что результат готов), «EndFoo» - это то, как вы получаете результат , В общем случае, если «Foo» может вызвать конкретное исключение, то это исключение может возникнуть либо из вызова «Начать», либо из «Конец», и вы должны быть готовы обрабатывать его в обоих местах.

В случае чего-то вроде Send(), который, возможно, возвращает пустоту? Я забыл), это немного раздражает/странно, потому что, поскольку это одностороннее, вы просто хотите «сгореть и забыть». Но исключения все еще могут произойти (например, я пытался отправить, но кто-то отключил мой сетевой кабель), и поэтому это может привести к исключениям ... и с учетом APM Begin/End такое исключение может возникнуть из вызова EndSend.Фактически, это исключение - это своего рода «результат» вызова «Отправить», и поэтому вы вызываете EndSend, чтобы система выдала вам исключение, чтобы сказать, что что-то пошло не так после того, как вы вызвали BeginSend.

+0

В ФОС IDuplexSessionChannel.BeginSend и EndSend имеет следующую подпись: IAsyncResult BeginSend (Message, AsyncCallback, объект) недействительным EndSend (IAsyncResult); Я вызываю EndSend из метода обратного вызова, который вызывается делегатом AsyncCallback, переданным BeginSend. Учитывая, что EndSend() возвращает void, я до сих пор не понимаю, для чего это нужно. «Результат», как я вижу, исходит от BeginSends AsyncCallback. Я также не понимаю, почему BeginSend возвращает IAsyncResult, когда он также возвращается асинхронно с помощью BeginSend AsyncCallback. – MrLane

+0

Чтение писем Brians снова через несколько месяцев после того, как я разместил этот вопрос, вещи МНОГО БОЛЬШЕ понятны с этим шаблоном. Это хорошо объясняет и книга WCF по программированию Юваля Лоури. Я до сих пор не знаю причины исключения, но он был устранен, поскольку я больше не вызываю EndSend(), поскольку я понимаю, что в любом случае результаты от него не возвращаются. Я не знаю, является ли это хорошей практикой (возможно, я мог бы пропустить детали исключения), но книга, похоже, предполагает, что ее можно опустить, а так как удаление вещей было намного лучше. – MrLane