Additional Information about Silverlight Client Timeout Value when calling a WCF WebService
Published Nov 16 2018 06:39 AM 733 Views
Microsoft
First published on MSDN on Nov 06, 2012

By default, a Silverlight client calling WCF uses the timeout settings documented here, http://msdn.microsoft.com/en-us/library/system.servicemodel.channels.binding.sendtimeout%28v=vs... .



  • SendTimeout, the default value is 1 minute.

  • ReceiveTimeout, the default value is 10 minutes.


If you have more data to send to server or you are using Silverlight client over a slow connection, 1 minute may not be enough. MSDN documents how you can use Silverlight ServicesReferences.ClientConfig binding setting to increase the client timeout, link: http://msdn.microsoft.com/en-us/library/cc197941(v=vs.95).aspx . But it may not always work as expected and it assumes Silverlight custom timeout value is always shorter than IE browser/WinINet default timeout. If the Silverlight timeout is not shorter than IE/WinINet default timeout, changing ServicesReferences.ClientConfig setting will not work.


For example, here is my timeout setting in my ServicesReferences.ClientConfig file. Yes, I am using a very extremely large scenario to demo the story.
<configuration>


<system.serviceModel>


<bindings>


<basicHttpBinding>


<bindingname="BasicHttpBinding_IService1"maxBufferSize="2147483647"


maxReceivedMessageSize="2147483647"


closeTimeout="00:59:00"


openTimeout="00:53:00"


receiveTimeout="03:15:00"


sendTimeout="03:21:00">


<securitymode="None" />


</binding>


</basicHttpBinding>


</bindings>


<client>


<endpointaddress="http://hzmain/WCFtest/Service1.svc"


binding="basicHttpBinding"


bindingConfiguration="BasicHttpBinding_IService1"  contract="ServiceReference1.IService1"


name="BasicHttpBinding_IService1" />


</client>


</system.serviceModel>


</configuration>


1) Let us look at WebRequest.RegisterPrefix("http://", WebRequestCreator.BrowserHttp) case, which is by default. And Silverlight uses BrowserHttp stack.


If we look at the send event, here is timer in Silverlight:


-> 0a7e2758 System.Threading.TimerQueueTimer


-> 0a7e26a8 System.Net.Browser.BrowserHttpWebRequest


-> 0a7e4cec MS.Internal.InternalWebRequest



0:002> !do 0a7e2758


Name:        System.Threading.TimerQueueTimer


MethodTable: 79509288


794f72a8  40005a8       20        System.UInt32  1 instance 12060000 m_dueTime


794f72a8  40005a9       24        System.UInt32  1 instance 4294967295 m_period


12060000 milliseconds = 12060 seconds = 201 minutes = sendTimeout="03:21:00"


So, the timeout value did get updated in IE browser from ServicesReferences.ClientConfig, but turns out, the change is only at System.Net.Browser.BrowserHttpWebRequest level to make timer trigger abort connection. However, as I learnt, the underlying WinINet connection still continues to use the default WinINet timeout.



Notice the callstack to show how Silverlight npctrl.dll is eventually calling into wininet.dll for HttpSendRequestExW to send out the request.


0:017> kL


ChildEBP RetAddr


056eaad4 750e31de WININET!HttpSendRequestExW


056eab18 750c1734 urlmon!CINetHttp::INetAsyncSendRequest+0x3fd


056eb33c 750c1b92 urlmon!CINetHttp::INetAsyncOpenRequest+0x335


056eb35c 750c10e3 urlmon!CINet::INetAsyncConnect+0x27d


056eb378 750bd1b2 urlmon!CINet::INetAsyncOpen+0x15a


056eb38c 750bd168 urlmon!CINet::INetAsyncStart+0x1d


056eb3a4 750bd3c7 urlmon!CINet::StartCommon+0x1dd


056eb3b8 750b98da urlmon!CINet::StartEx+0x1a


056eb3ec 750b8d2b urlmon!COInetProt::StartEx+0xc1


056eb450 750ba097 urlmon!CTransaction::StartEx+0x40b


056eb4ec 750a386c urlmon!CBinding::StartBinding+0x883


056eb558 5cfb3ace urlmon!operator new+0x20


056ec664 5cfb40ca npctrl!CWindowsDownloadRequest::_Download+0x446


056ed8d0 5cfb431d npctrl!CWindowsDownloadRequest::InitiateRequest+0x5ea


056ed938 5cfb3835 npctrl!CXcpBrowserHost::ProcessAsyncDownloadRequest_BrowserImpl+0x2a7


056ed980 5cfb36ef npctrl!CXcpBrowserHost::ProcessAsyncDownloadRequest+0x117


056ed9c0 5cfb3526 npctrl!CDownloadRequest::Download+0x4f


056ed9e0 5cfb34cd npctrl!CAsyncDownloadRequestManager::DownloadRequests+0x48


056ed9f4 5cfa48a4 npctrl!CXcpDispatcher::OnWindowMessage+0x114


056eda0c 5cfa3270 npctrl!CXcpDispatcher::ProcessMessage+0xa2



If you continue debugging into the HttpSendRequestExW first parameter of  hRequest = 0x00cc000c handle with debugging symbol, you will see the IE/WinINet timeout, such as SendTimeOut and ReceiveTimeOut, is still using the default IE timeout value. It is not modified by your ServicesReferences.ClientConfig setting of timeout.



2) Now, let us look at ClientHttp case, i.e. WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp):


Note: For the difference between ClientHttp vs BrowserHttp handling in Silverlight, please check MSDN http://msdn.microsoft.com/en-us/library/dd920295%28v=VS.95%29.aspx .


Now it is Silverlight npctrl.dll / npctrl!CWindowsOSWebRequest class still calling WinINet. The difference is: It is calling Wininet.dll directly instead of UrlMon build-in BrowserHttp stack. So, ClientHttp implementation is still on top of wininet.dll for underlying connection instead of winsock in order to avoid ClientHttp implementing the protocol details.


Callstack:


0:044> kL


ChildEBP RetAddr


0ea5f954 5cfb933e WININET!HttpSendRequestW


0ea5fac0 5cfb8b71 npctrl!CWindowsOSWebRequest::DoOperatingSystemWebRequest+0xbd4


0ea5faf0 5e29027b npctrl!COperatingSystemWebRequest::OperatingSystemWebRequestThreadFn+0x60


0ea5fb08 7689339a IEFRAME!_Detour_ThreadProc+0x23


0ea5fb14 77319ef2 kernel32!BaseThreadInitThunk+0xe


0ea5fb54 77319ec5 ntdll!__RtlUserThreadStart+0x70


0ea5fb6c 00000000 ntdll!_RtlUserThreadStart+0x1b


If you debug into the WININET!HttpSendRequestW handle level, you will see the WinINet is still using IE default SendTimeout value instead of your ServicesReferences.ClientConfig timeout value.


But, again, .NET level timer is 3:21 hours, which is much longer than WinINet layer can possibly even keep the connection.


0:044> !do 0acf6594


Name:        System.Threading.TimerQueueTimer


MethodTable: 79509288


EEClass:     790b83e0


Size:        52(0x34) bytes


File:        C:\Program Files (x86)\Microsoft Silverlight\5.1.10411.0\mscorlib.dll


Fields:


MT    Field   Offset                 Type VT     Attr    Value Name


79509288  40005a5        4 ...g.TimerQueueTimer  0 instance 00000000 m_next


79509288  40005a6        8 ...g.TimerQueueTimer  0 instance 00000000 m_prev


794f71d4  40005a7       1c         System.Int32  1 instance 495612727 m_startTicks


794f72a8  40005a8       20        System.UInt32  1 instance 12060000 m_dueTime


12060000 milliseconds = 12060 seconds = 201 minutes = sendTimeout="03:21:00"


So, you can see Silverlight creates WinINet connection as the underlying connection implementation. But when you create your own wcf Silverlight client timeout values in ServicesReferences.ClientConfig, a timer is created at .NET layer, but doesn't modify the underlying WinINet timeout values, which includes both SendTimeOut and RecieveTimeOut for WinINet. It will work only if your timeout setting in ServicesReferences.ClientConfig is less than or equal to IE/WinINet timeout setting.


So, how can we also update the SendTimeOut and ReceiveTimeout at IE WinINet level for my Silverlight client?


Answer: We can only do it through IE regkey (applies to IE browser only). Here is the location and key name:


[HKCU\Software\Microsoft\windows\currentversion\internet settings\]


ReceiveTimeout


DWORD in Millisecond unit


SendTimeout


DWORD in Millisecond unit


Version history
Last update:
‎Nov 16 2018 06:39 AM
Updated by: