English 中文(简体)
How do I stop WCF from message pumping while it is waiting on a synchronous call?
原标题:

I have a situation where a basic message, such as wm_paint, inside it s treatment will trigger a call WCF Webservices when, for example, it needs remote formatting information.

However, while WCF is waiting for that call to return, messages keep being pumped, which can end up in another message triggering the same call.

-Thread safety does not help my problem since this is "fake" multithreading - it s always the same thread interpreting the messages from the pump.

-Reentrancy safety does not help me, since the second call needs the remote information to execute correctly.

See the following (simplified) call stack :

    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()

I ve cut the top of the callstack, but you can see where this is going by the presence of the line MyService.DoSomething(System.String) twice in the call stack.

We see that somewhere in there, there s a call to System.Threading.WaitHandle.WaitOne(Int64, Boolean).

I suspect that it s passing "true" as to the second parameter (exitSynchronisationContext) which thus allows the message pump to keep pumping.

Is there any way to avoid this default behavior by WCF?

问题回答

You re invoking a WCF call in response to a WM_PAINT!? That seems pretty horrible to me. :/

Even if you could force the message pump to stop, you ll end up with an unresponsive GUI while the call completes. What if there is a network timeout or some other reason that the call takes several seconds?

Can you not preload the information required? Or at the very least lazy load so the WCF call only gets invokes once. This way you could also set a flag in the load method to indicate whether the call is already in progress.





相关问题
Bring window to foreground after Mutex fails

I was wondering if someone can tell me what would be the best way to bring my application to the foreground if a mutex was not able to be created for a new instance. E.g.: Application X is running ...

How to start WinForm app minimized to tray?

I ve successfully created an app that minimizes to the tray using a NotifyIcon. When the form is manually closed it is successfully hidden from the desktop, taskbar, and alt-tab. The problem occurs ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

Handle DataTable.DataRow cell change event

I have a DataTable that has several DataColumns and DataRow. Now i would like to handle an event when cell of this DataRow is changed. How to do this in c#?

Apparent Memory Leak in DataGridView

How do you force a DataGridView to release its reference to a bound DataSet? We have a rather large dataset being displayed in a DataGridView and noticed that resources were not being freed after the ...

ALT Key Shortcuts Hidden

I am using VS2008 and creating forms. By default, the underscore of the character in a textbox when using an ampersand is not shown when I run the application. ex. "&Goto Here" is not ...

WPF-XAML window in Winforms Application

I have a Winforms application coded in VS C# 2008 and want to insert a WPF window into the window pane of Winforms application. Could you explain me how this is done.

热门标签