Async End <Method>не вызывается в WCF - PullRequest
       11

Async End <Method>не вызывается в WCF

0 голосов
/ 13 сентября 2009

У меня следующая ситуация: моя служба WCF позволяет клиенту зарегистрироваться для ожидания какого-либо события. Ожидание является асинхронным на стороне службы, то есть официант регистрируется, и когда процесс завершается, официант получает уведомление. На данный момент это просто ManualResetEvent.

Теперь я хочу показать этот метод через WCF. Я попытался использовать AsyncPattern=true и создал два метода: BeginWait, который связывает событие в IAsyncResult, и EndWait, который вызывает AsyncWaitHandle.WaitOne(). Однако, если я звоню BeginWait, EndWait с клиента, серверная сторона EndWait не выполняется. Я использую реализованную вручную оболочку (мой прокси-класс является производным от ChannelBase<IWaitService>, IWaitService), который в основном вызывает Channel.EndWait(), и эта функция действительно вызывается; но на стороне сервера звонок не приходит.

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

Ответы [ 2 ]

2 голосов
/ 29 июля 2011

Линия

var task = Task.Factory.StartNew(() => IsPrime(a));  

использует перегрузку

TaskFactory.StartNew(Action)

, что приводит к

((IAsyncResult)task).AsyncState == null

вызов callback (task) приводит к ArgumentException, жалуясь, что объект состояния отличается от объекта состояния, который был передан методу BeginXxx Строка должна быть изменена на

var task = Task.Factory.StartNew((actionState) => IsPrime(a), state);  

с использованием перегрузки

TaskFactory.StartNew(Action<object>, object)

такой, что объект состояния, переданный WCF, попадает в задачу:

((IAsyncResult)task).AsyncState.GetType().FullName == System.ServiceModel.Dispatcher.MessageRpc+Wrapper
0 голосов
/ 23 мая 2011

Синхронное / асинхронное решение может быть принято независимо на стороне сервера или клиента. Вызов EndWait на клиенте не переводится в вызов EndWait на сервере. Я бы порекомендовал протестировать асинхронную службу с клиентом синхронизации, чтобы упростить задачу и избежать путаницы.

Я бы также рекомендовал вам не вызывать WaitOne внутри метода EndWait. Контракт заключается в том, что этот метод будет вызываться только после того, как IAsyncResult сообщит платформе, что это сделано. Это делается одним из трех способов:

  • CompletedSynchronically возвращает true
  • Вызывается AsyncCallback
  • AsyncWaitHandle сигнализируется

CompletedSynchronously должен возвращать true, только если BeginWait имел достаточно информации для завершения запроса до его возврата. Это, вероятно, не тот случай. Вы можете выполнить два других условия с помощью ManualResetEvent следующим образом:

class EventBasedAsyncResult : IAsyncResult
{
    private readonly ManualResetEvent _manualResetEvent;
    private readonly AsyncCallback _asyncCallback;
    private readonly object _asyncState;

    public EventBasedAsyncResult(AsyncCallback callback, object asyncState)
    {
        _manualResetEvent = new ManualResetEvent(false);
        _asyncState = asyncState;
        _asyncCallback = callback;
    }

    public void WaitCompleted()
    {
        _manualResetEvent.Set();
        _asyncCallback(this);
    }

    public object AsyncState
    {
        get { return _asyncState; }
    }

    public WaitHandle AsyncWaitHandle
    {
        get { return _manualResetEvent; }
    }

    public bool CompletedSynchronously
    {
        get { return false; }
    }

    public bool IsCompleted
    {
        get { return _manualResetEvent.WaitOne(0); }
    }
}

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

...