如何在等待同步呼叫时阻止WCF从消息中吸收?

时间:2009-12-02 21:57:10

标签: winforms wcf message-queue

我遇到一种情况,例如wm_paint内部的基本消息会触发调用WCF Webservices,例如,它需要远程格式化信息。

但是,当WCF正在等待该呼叫返回时,消息仍然被抽取,这可能会导致另一条消息触发相同的呼叫。

- 线程安全对我的问题没有帮助,因为这是“假的”多线程 - 它始终是解释来自泵的消息的相同线程。

-Reentrancy安全对我没有帮助,因为第二次调用需要远程信息才能正确执行。

请参阅以下(简化)调用堆栈:

    MyService.DoSomething(System.String)
    [...]
    Grid.OnPaint(System.Windows.Forms.PaintEventArgs)   System.Windows.Forms.Control.PaintWithErrorHandling(System.Windows.Forms.PaintEventArgs, Int16, Boolean)
    System.Windows.Forms.Control.WmPaint(System.Windows.Forms.Message ByRef)
    System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)
    System.Windows.Forms.ContainerControl.WndProc(System.Windows.Forms.Message ByRef)
    System.Windows.Forms.Control+ControlNativeWindow.OnMessage(System.Windows.Forms.Message ByRef)
    System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows.Forms.Message ByRef)
    System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)
    System.Threading.WaitHandle.WaitOneNative(Microsoft.Win32.SafeHandles.SafeWaitHandle, UInt32, Boolean, Boolean)
    System.Threading.WaitHandle.WaitOne(Int64, Boolean)
    System.Threading.WaitHandle.WaitOne(Int32, Boolean)
    System.Net.LazyAsyncResult.WaitForCompletion(Boolean)
    System.Net.Connection.SubmitRequest(System.Net.HttpWebRequest)
    System.Net.ServicePoint.SubmitRequest(System.Net.HttpWebRequest, System.String)
    System.Net.HttpWebRequest.SubmitRequest(System.Net.ServicePoint)
    System.Net.HttpWebRequest.GetRequestStream(System.Net.TransportContext ByRef)
    System.Net.HttpWebRequest.GetRequestStream()
    System.ServiceModel.Channels.HttpOutput+WebRequestHttpOutput.GetOutputStream()
    System.ServiceModel.Channels.HttpOutput.Send(System.TimeSpan)
    System.ServiceModel.Channels.HttpChannelFactory+HttpRequestChannel+HttpChannelRequest.SendRequest(System.ServiceModel.Channels.Message, System.TimeSpan)
    System.ServiceModel.Channels.RequestChannel.Request(System.ServiceModel.Channels.Message, System.TimeSpan)
    System.ServiceModel.Channels.SecurityChannelFactory1+SecurityRequestChannel[[System.__Canon, mscorlib]].Request(System.ServiceModel.Channels.Message, System.TimeSpan)
    System.ServiceModel.Dispatcher.RequestChannelBinder.Request(System.ServiceModel.Channels.Message, System.TimeSpan)
    System.ServiceModel.Dispatcher.ProxyOperationRuntime, System.Object[], System.Object[], System.TimeSpan)
    System.ServiceModel.Dispatcher.ProxyOperationRuntime, System.Object[], System.Object[])
    System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage, System.ServiceModel.Dispatcher.ProxyOperationRuntime)
    System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)
    System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32)
    [...]
    MyService.DoSomething(System.String)
    [...]
    System.Windows.Forms.Control.WmMouseUp(System.Windows.Forms.Message ByRef, System.Windows.Forms.MouseButtons, Int32)
    System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)
    System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows.Forms.Message ByRef)
    System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)
System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG ByRef)
System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)
    System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)
    System.Windows.Forms.ApplicationContext)
    System.Windows.Forms.Application.Run(System.Windows.Forms.Form)
    [...]
    MyApplication.Main()

我已经切断了callstack的顶部,但你可以通过在调用堆栈中存在MyService.DoSomething(System.String)行两次来查看它的位置。

我们看到那里的某个地方,有一个对System.Threading.WaitHandle.WaitOne(Int64,Boolean)的调用。

我怀疑它对第二个参数(exitSynchronisationContext)传递“true”,因此允许消息泵继续泵送。

WCF有什么方法可以避免这种默认行为吗?

1 个答案:

答案 0 :(得分:2)

您正在调用WCF调用以响应WM_PAINT!?这对我来说似乎很可怕。 :/

即使您可以强制停止消息泵,您也会在呼叫完成时以无响应的GUI结束。如果网络超时或其他原因导致呼叫需要几秒钟,该怎么办?

你能预先加载所需的信息吗?或者至少是延迟加载,因此WCF调用只会调用一次。这样,您还可以在load方法中设置一个标志,以指示调用是否已在进行中。