none
WCF doesn't time out after the specified timeout

    Question

  • I have a WCF app that I'm trying to get to timeout after a small timeout interval. I've adjusted the timeouts to about 2 seconds, but the code will hang for about 22 seconds when I attempt to call Open() on the proxy object. I get an EndpointNotFoundException with message "Could not connect to net.tcp://10.22.104.64:6789/MyContract. The connection attempt lasted for a time span of 00:00:01.9062500. TCP error code 10060: A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond."

    Obviously the code thinks it's timing out in 2 seconds, but in reality the Open call blocks for far longer. A client that's running responds perfectly within this interval of time. Any ideas?

    // Example code that calls the proxy

    ...
    try
    {
    MyProxy.GetProxy(IPAddress.Parse("10.22.104.64"), 6789, validator).Open()
    }
    catch (EndPointNotFoundException)
    {
    // Exception caught here indicates the timeout occurred after just under 2 seconds, but in reality it was about 22
    }
    ....

    // Example code that creates the proxy

    public class MyProxy : ClientBase<IMyContract>, IMyContract
    {

    ......

    public static MyProxy GetProxy(IPAddress ipAddress, int port, X509CertificateValidator validator)
    {
    // Create a TCP binding
    // Require transport security, encryption/signatures, and a client certificate
    NetTcpBinding tcpBinding = new NetTcpBinding(SecurityMode.Transport);
    tcpBinding.Security.Transport.ClientCredentialType = TcpClientCredentialType.None;
    tcpBinding.Security.Transport.ProtectionLevel = ProtectionLevel.EncryptAndSign;

    // Timeouts
    TimeSpan ts = TimeSpan.FromSeconds(2);
    tcpBinding.CloseTimeout = ts;
    tcpBinding.OpenTimeout = ts;
    tcpBinding.ReceiveTimeout = ts;
    tcpBinding.SendTimeout = ts;

    // Create a TCP address
    Uri tcpAddress = new Uri("net.tcp://" + ipAddress.ToString() + ":" + port.ToString() + "/MyContract");

    // Create a DNS identity based on what the remote host's certificate will claim
    DnsEndpointIdentity tcpIdentity = new DnsEndpointIdentity("MyClientName");

    // Create the TCP endpoint
    EndpointAddress tcpEndpoint = new EndpointAddress(tcpAddress, tcpIdentity);

    // Create the proxy
    MyProxy proxy = new MyProxy(tcpBinding, tcpEndpoint);

    // Enable custom validation of the server's certificate
    proxy.ClientCredentials.ServiceCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.Custom;
    proxy.ClientCredentials.ServiceCertificate.Authentication.CustomCertificateValidator = validator;

    return proxy;
    }

    ....

    }
    Saturday, June 09, 2007 12:36 AM

All replies

  • I wonder how long it takes to return the proxy after your call to GetProxy.  Not that this would take 20 seconds, but it can help to isolate the problem.  My guess is that there is a lot of stuff going on during Open that don't count towards the Open timeout.  Things like setting up the secure channel, the transaction layer, etc.  That's just a guess, though.

     

    -James

    Monday, June 11, 2007 10:58 PM
    Moderator
  • I would have thought that too, except that if the target machine is up and running, the code will open the channel, perform a requested operation, and close the channel in under 2 seconds.

    As a workaround, I've found that by using the asynchronous open, I can ensure I only wait 2 seconds before giving up, but I'd really prefer to just be able to call my method on the Channel object and not worry about it not enforcing my timeouts. Also, I think it's funny that the error returned shows that the underlying class that's being used for TCP gives up after 2 seconds, but it takes well over 20 for the entire operation to abort.
    Tuesday, June 12, 2007 7:17 PM
  • This is a long shot, but are you using InfoCard or something that uses an IInteractiveChannelInitializer?  That portion of the 'Open' call doesn't run under the timeout (since it is designed to pop up UI and wait for human interaction).  But I doubt this is the issue here (if it were, you probably wouldn't be asking the question).

     

    Can you break in the debugger during this 'wait' and capture a call stack?

    Tuesday, June 12, 2007 7:22 PM
  • I encounter the same problem as described above. Depending on the address used, it takes about 21 to 22 seconds before anything happens with the first call to the service. With anything I mean a normal response from the service, an exception, etc. It does not matter whether you use certificates or any other custom security. Also, svcutil.exe and Internet Explorer block as well for abound 22 seconds when you try to access your service.

     

    I found out that if you make another call to the service, the call returns immediatly as expected. Therefore, the delay seems to be during the connection process of the WCF service.

     

    Changing the base address is one of the only ways to influent the internal connection process as far as I know. So I tried this. I changed the base address from http://d620jhs/... (d620jhs is my computer name) to http://localhost/.... This made everything work perfectly (no delays that is). To me, this behavior is quite strange and unexpected.

     

    For your information, my computer is not part of a domain and has a DNS suffix. The latter might be part of the problem: when I add a line to the HOSTS file where I map my computer name (d620jhs) to 127.0.0.1, the delay disappears as well. Therefore, it seems to me that it takes WCF about 22 seconds to search the network and find the right computer. I do not experience any similar problems with other software.

     

    I hope this helps. Best regards,

     

    Johan Stokking

    Wednesday, August 15, 2007 11:04 PM
  • I've got the same problem and I've found a way to solve it.

     

    The 22 second timeout is due to the connection timeout of the sockets WCF uses. Unfortunately, this connection timeout isn't configurable but is fixed by the operating system.

     

    This forum thread

     

    http://channel9.msdn.com/forums/TechOff/41602-TcpClient-or-Socket-Connect-timeout/

     

    gave me the right idea:

     

    Code Snippet

    Dim oAsyncResult As IAsyncResult

    Dim fOpenCompleted As Boolean

     

    oAsyncResult = proxy.BeginOpen(Nothing, Nothing)

    fOpenCompleted = oAsyncResult.AsyncWaitHandle.WaitOne(connectionTimeoutInMilliseconds, True)

     

    If fOpenCompleted Then

      'All right proxy open

      proxy.EndOpen(oAsyncResult)

    Else

      'Timeout elapsed!

      proxy.Close()

      Throw New ApplicationException

    End If

     

    The trick is using BeginOpen and the WaitHandle returned in the IAsyncResult to wait a specified "connection timeout" for the opening of the proxy. If we return from the WaitOne because BeginOpen terminated, then we call EndOpen and we can use the proxy; otherwise, we close the proxy and throw an exception (or do something else).

     

    Note that the BeginOpen overload with the timeout parameter doesn't work - we have to use the wait handle.

     

    Hope this helps.

     

    Monday, July 14, 2008 4:23 PM
  • I have the same problem. Is there a cleaner way to solve this?
    Friday, July 20, 2012 6:00 PM