The first WCF call always timed out?
This is a scenario where both the WCF client and service are running in the same AppDomain inside a MVC application. The WC F call originates from MVC controller. In addition, the WCF service host was created in the same function as well. The code looks like:
public ActionResult Index() { //Create the service host ServiceHost host = new ServiceHost(typeof(HelloWorld)); host.Open(); //Create the client EndpointAddress address = new EndpointAddress("net.pipe://localhost/WCFSelfHostInMVC/HelloWorld"); NetNamedPipeBinding binding = new NetNamedPipeBinding(); binding.Security.Mode = NetNamedPipeSecurityMode.None; ChannelFactory<IHelloWorld> factory = new ChannelFactory<IHelloWorld>(binding, address); IHelloWorld channel = factory.CreateChannel(); // Calling the service ViewBag.Message = channel.DoWork(); return View(); } |
We captured a dump, and found it is a deadlock scenario. The WCF client was owning a lock(AspNetSynchronizationContext) and waiting the response of the service. However, the service tried to lock AspNetSynchronizationContext object as well to handle the request.
Here is the stack of client, which was waiting the response from service. This thread owns the lock of AspNetSynchronizationContext object.
0:025:x86> ~22kL ChildEBP RetAddr 04b1df34 74f90bdd ntdll_77320000!ZwWaitForMultipleObjects+0x15 04b1dfd0 76681a2c KERNELBASE!WaitForMultipleObjectsEx+0x100 04b1e018 6dcff2ca kernel32!WaitForMultipleObjectsExImplementation+0xe0 04b1e07c 6dcff0f8 clr!WaitForMultipleObjectsEx_SO_TOLERANT+0x56 04b1e09c 6dcfef38 clr!Thread::DoAppropriateAptStateWait+0x4d 04b1e130 6dcfeff9 clr!Thread::DoAppropriateWaitWorker+0x17d 04b1e19c 6ddd9d46 clr!Thread::DoAppropriateWait+0x60 04b1e29c 025cb5ef clr!WaitHandleNative::CorWaitOneNative+0x196 04b1e2b4 025ab1ee mscorlib_ni!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle, Int64, Boolean, Boolean)+0x2b 04b1e2d8 500cf2fc mscorlib_ni!System.Threading.WaitHandle.WaitOne(System.TimeSpan, Boolean)+0x6e 04b1e2f0 016042f0 System_Runtime_DurableInstancing_ni!System.Runtime.TimeoutHelper.WaitOne(System.Threading.WaitHandle, System.TimeSpan)+0x6c 04b1e308 517cbef8 System_ServiceModel_ni!System.ServiceModel.Channels.OverlappedContext.WaitForSyncOperation(System.TimeSpan, System.Object ByRef)+0x40 04b1e32c 517cb1bf System_ServiceModel_ni!System.ServiceModel.Channels.PipeConnection.WaitForSyncRead(System.TimeSpan, Boolean)+0x38 ……. 04b1e6f8 5179fb05 System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(System.Runtime.Remoting.Messaging.IMethodCallMessage, System.ServiceModel.Dispatcher.ProxyOperationRuntime)+0x59 04b1e740 0258a25e System_ServiceModel_ni!System.ServiceModel.Channels.ServiceChannelProxy.Invoke(System.Runtime.Remoting.Messaging.IMessage)+0x65 04b1e774 6dcc2336 mscorlib_ni!System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(System.Runtime.Remoting.Proxies.MessageData ByRef, Int32)+0xee |
This thread is the service thread. However, this thread was trying to lock the AspNetSynchronizationContext object owned by thread 22. This results in the deadlock.
0:025:x86> kL ChildEBP RetAddr 053beba0 74f90bdd ntdll_77320000!ZwWaitForMultipleObjects+0x15 053bec3c 76681a2c KERNELBASE!WaitForMultipleObjectsEx+0x100 053bec84 6dcff2ca kernel32!WaitForMultipleObjectsExImplementation+0xe0 053bece8 6dcff0f8 clr!WaitForMultipleObjectsEx_SO_TOLERANT+0x56 …….. 053bef00 6ddd25a6 clr!AwareLock::EnterEpilogHelper+0xa8 053bef40 6ddd25eb clr!AwareLock::EnterEpilog+0x42 053bef60 6ddf78d1 clr!AwareLock::Enter+0x5f 053bf01c 025ce0c4 clr!JIT_MonReliableEnter_Portable+0x104 053bf02c53ef5477 mscorlib_ni!System.Threading.Monitor.Enter(System.Object, Boolean ByRef)+0x14 053bf05c 53ef55e9 System_Web_ni!System.Web.AspNetSynchronizationContext.CallCallback(System.Threading.SendOrPostCallback, System.Object)+0x53 053bf084 517bec09 System_Web_ni!System.Web.AspNetSynchronizationContext.Post(System.Threading.SendOrPostCallback, System.Object)+0x9 ……. 053bf164 517bd65b System_ServiceModel_ni!System.ServiceModel.Dispatcher.MessageRpc.Process(Boolean)+0xff ………………………….. |
In short, the service thread was trying to lock the object(AspNetSynchronizationContext) owned by the WCF client thread, but client thread was blocked and waiting the service call back.
1. The WCF client thread (MVC thread) was holding the AspNetSynchronizationContext lock as it is an ASP.NET request and it was waiting the response of WCF service call.
2. The WCF service thread was waiting for the AspNetSynchronizationContext lock to process the WCF request.
The reasons WCF is using the AspNetSynchronizationContext are:
- The ServiceBehavior – UseSynchronizationContext is set to true (by default).
- The WCF service host is created under ASP.NET context (As the code demoed, it was created inside the MCV controller.)
There are several workarounds:
1. Setting UseSynchronizationContext to false.
2. Creating the service host in the Application_Start
3. Using the Service.svc file.
In addition, only .Net 4.0 has this problem, .Net 3.5 doesn’t have this issue.
Wei from APGC DSI Team