Как остановить WCF от прокачки сообщений, пока он ожидает синхронного вызова? - PullRequest
2 голосов
/ 03 декабря 2009

У меня есть ситуация, когда основное сообщение, такое как 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?

1 Ответ

2 голосов
/ 27 октября 2011

Вы вызываете вызов WCF в ответ на WM_PAINT !? Это кажется довольно ужасным для меня. : /

Даже если бы вы могли принудительно остановить рассылку сообщений, вы получите безотзывный графический интерфейс, когда вызов завершится. Что если есть сетевое время ожидания или какая-то другая причина, по которой вызов занимает несколько секунд?

Не можете ли вы предварительно загрузить необходимую информацию? Или, по крайней мере, ленивая загрузка, поэтому вызов WCF вызывается только один раз. Таким образом, вы также можете установить флаг в методе загрузки, чтобы указать, выполняется ли уже вызов.

...