【问题标题】:Async End<Method> not called in WCFWCF 中未调用异步 End<Method>
【发布时间】:2011-07-30 00:11:23
【问题描述】:

我有以下情况:我的 WCF 服务允许客户端注册以等待某些事件。等待在服务端是异步的,即注册服务员,当进程完成后,通知服务员。目前,它只是一个ManualResetEvent。

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

我在这里做错了什么?后续问题:如果异步调用正常工作,有没有一种简单的方法可以在客户端实现同步?

【问题讨论】:

  • 您可能想查看blogs.msdn.com/mjm/archive/2005/05/04/414793.aspx 主要是为了知道sync-versus-async 是一个“本地”的东西(您可以从客户端调用方法同步或异步,这可能会被实现在服务器上同步或异步,两者没有任何关系)。
  • 基本上,那篇博文解决了它——你能从你的评论中回答一下,这样我就可以接受了吗?

标签: wcf asynchronous-wcf-call


【解决方案1】:

线

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

使用重载

TaskFactory.StartNew(Action)

导致

((IAsyncResult)task).AsyncState == null

对回调(任务)的调用导致 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

【讨论】:

    【解决方案2】:

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

    我进一步建议您不要在 EndWait 方法中调用 WaitOne。约定是只有在 IAsyncResult 告诉框架它完成后才会调用此方法。这是通过以下三种方式之一完成的:

    • CompletedSynchronously 返回 true
    • AsyncCallback 被调用
    • AsyncWaitHandle 发出信号

    CompletedSynchronously 应该仅在 BeginWait 有足够的信息来完成请求之前返回 true。情况可能并非如此。您可以使用 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 被调用了,即使客户端是同步的。

    【讨论】:

      猜你喜欢
      • 2012-10-03
      • 1970-01-01
      • 1970-01-01
      • 2011-08-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多