I did a lot of research and could not find a solution or answer to this question. I have a test application that I wrote to show a "problem". (I am open to the idea that this is just how WCF works, and there is nothing I can do about it.)
My test application is a simple WCF service and client with the created Visual Studio proxy. I specify a proxy on a remote computer that works, but does not start the service. This point is important. If the remote computer is not running at all, the WCF call ends immediately.
The client application creates an instance of the client proxy class, starts a new task, and then tries to make a call to the service interface, which will be blocked because the service on the other end does not exist. The background task sleeps for 5 seconds and then closes the proxy. I expected another thread to be immediately at fault when the proxy was shut down, but that is not the case. About 20 seconds after the initial call, it will be faulty.
Here is my client code:
using System; using System.ServiceModel; using System.Threading; using System.Threading.Tasks; using TestConsoleClient.MyTestServiceReference; namespace TestConsoleClient { class Program { static void Main(string[] args) { MyTestServiceClient client = new MyTestServiceClient(); // Start new thread and wait a little bit before trying to close connection. Task.Factory.StartNew(() => { LogMessage("Sleeping for 5 seconds ..."); Thread.Sleep(5000); if (client == null) { LogMessage("Woke up! Proxy was closed before waking up."); return; } LogMessage("Woke up! Attempting to abort connection."); LogMessage(string.Format("Channel state before Close: {0}", ((ICommunicationObject)client).State)); client.Close(); ((IDisposable)client).Dispose(); client.Abort(); // Channel state is Closed, as expected, but blocked thread does not wake up? LogMessage(string.Format("Channel state after Abort: {0}", ((ICommunicationObject)client).State)); client = null; }); // Start connecting. LogMessage("Starting connection ..."); try { LogMessage("Calling MyTestService.DoWork()"); client.DoWork(); // Timeout is 60 seconds. State is "Connecting" } catch (Exception ex) { LogMessage(string.Format("Exception caught: {0}", ex.Message)); if (client != null) { client.Abort(); ((IDisposable) client).Dispose(); client = null; } } finally { if (client != null) { client.Close(); client = null; } } LogMessage("Press Enter to exit ..."); Console.ReadLine(); } private static void LogMessage(string msg) { Console.WriteLine("{0}: [{1}] {2}", DateTime.Now.ToString("hh:mm:ss tt"), Thread.CurrentThread.ManagedThreadId, msg); } } }
And here is the result of my program:
01:48:31 PM: [9] Starting connection ... 01:48:31 PM: [9] Calling MyTestService.DoWork() 01:48:31 PM: [10] Sleeping for 5 seconds ... 01:48:36 PM: [10] Woke up! Attempting to abort connection. 01:48:36 PM: [10] Channel state before Close: Opening 01:48:36 PM: [10] Channel state after Abort: Closed 01:48:54 PM: [9] Exception caught: Could not connect to net.tcp://th-niconevm:80 80/MyTestService. The connection attempt lasted for a time span of 00:00:22.0573 009. TCP error code 10060: A connection attempt failed because the connected par ty did not properly respond after a period of time, or established connection fa iled because connected host has failed to respond 10.10.10.10:8080. 01:48:54 PM: [9] Press Enter to exit ...
What I'm trying to do is let the user disconnect so that they can make the necessary corrections and then try again. As you can see in the output, after that the channel switches from the "Open" state to the "Closed" state, but the service call remains blocked until it expires. I can, of course, get around this, but there seems to be a way to interrupt it.
Here is the app.config client:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <bindings> <netTcpBinding> <binding name="NetTcpBinding_IMyTestService" closeTimeout="00:01:00" openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false" transferMode="Buffered" transactionProtocol="OleTransactions" hostNameComparisonMode="StrongWildcard" listenBacklog="10" maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10" maxReceivedMessageSize="65536"> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" /> <reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" /> <security mode="Transport"> <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" /> <message clientCredentialType="Windows" /> </security> </binding> </netTcpBinding> </bindings> <client> <endpoint address="net.tcp://remotehost:8080/MyTestService" binding="netTcpBinding" bindingConfiguration="NetTcpBinding_IMyTestService" contract="MyTestServiceReference.IMyTestService" name="NetTcpBinding_IMyTestService"> <identity> <userPrincipalName value="remotehost\ClientUser" /> </identity> </endpoint> </client> </system.serviceModel> </configuration>