在WCF </method>中未调用Async End <method>

时间:2009-09-13 18:10:52

标签: wcf asynchronous-wcf-call

我有以下情况:我的WCF服务允许客户端注册以等待某个事件。等待在服务端是异步的,即服务员被注册,并且当过程结束时,服务员被通知。目前,它只是一个ManualResetEvent

现在我想通过WCF公开这个方法。我尝试使用AsyncPattern=true并创建了两个方法,BeginWait将事件捆绑为IAsyncResultEndWait调用AsyncWaitHandle.WaitOne()。但是,如果我从客户端调用BeginWaitEndWait,则不会执行服务器端EndWait。我正在使用手动实现的包装器(我的代理类派生自ChannelBase<IWaitService>, IWaitService),它基本上调用Channel.EndWait(),并且确实调用了此函数;但是在服务器端,呼叫永远不会到来。

我在这里做错了什么?后续问题:如果异步调用正在运行,是否有一种简单的方法可以在客户端进行同步?

2 个答案:

答案 0 :(得分:2)

该行

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

答案 1 :(得分:0)

同步/异步决策可以在服务器或客户端独立进行。在客户端上调用EndWait不会转换为服务器上的EndWait调用。我建议使用同步客户端测试异步服务,以保持简单并避免混淆。

我还建议你不要在EndWait方法中调用WaitOne。合同是只有在IAsyncResult告诉框架它完成后才会调用此方法。这可以通过以下三种方式之一完成:

  • CompletedSynchronously返回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。