views:

195

answers:

0

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?