我有以下情况:我的WCF服务允许客户端注册以等待某个事件。等待在服务端是异步的,即服务员被注册,并且当过程结束时,服务员被通知。目前,它只是一个ManualResetEvent
。
现在我想通过WCF公开这个方法。我尝试使用AsyncPattern=true
并创建了两个方法,BeginWait
将事件捆绑为IAsyncResult
,EndWait
调用AsyncWaitHandle.WaitOne()
。但是,如果我从客户端调用BeginWait
,EndWait
,则不会执行服务器端EndWait
。我正在使用手动实现的包装器(我的代理类派生自ChannelBase<IWaitService>, IWaitService
),它基本上调用Channel.EndWait()
,并且确实调用了此函数;但是在服务器端,呼叫永远不会到来。
我在这里做错了什么?后续问题:如果异步调用正在运行,是否有一种简单的方法可以在客户端进行同步?
答案 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,如果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。