У меня есть ситуация, когда основное сообщение, такое как wm_paint, внутри его обработки вызовет вызов веб-служб WCF, когда, например, ему нужна информация об удаленном форматировании.
Однако, пока WCF ожидает возврата этого вызова, сообщения продолжают перекачиваться, что может привести к другому сообщению, инициирующему тот же вызов.
-Безопасность нитей не помогает моей проблеме, так как это «фальшивая» многопоточность - это всегда один и тот же поток, интерпретирующий сообщения от насоса.
-Безопасность входа не помогает, так как для второго вызова требуется правильная удаленная информация.
См. Следующий (упрощенный) стек вызовов:
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()
Я сократил вершину стека вызовов, но вы можете увидеть, где это происходит, по наличию строки MyService.DoSomething (System.String) в стеке вызовов.
Мы видим, что где-то там есть вызов System.Threading.WaitHandle.WaitOne (Int64, Boolean).
Я подозреваю, что он передает "true" во втором параметре (exitSynchronisationContext), который, таким образом, позволяет насосу сообщений продолжать прокачку.
Есть ли способ избежать этого поведения по умолчанию WCF?