How to interrupt a WCF proxy blocked in connection state because the remote service is not running

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> 
+7
source share
1 answer

You can get more mileage if you create your proxy class with asynchronous operations, then your code will become much simpler.

 // Asynchronously call DoWork MyTestServiceClient client = new MyTestServiceClient(); IAsyncResult iar = client.BeginDoWork(null, null); // Sleep, dance, do the shopping, whatever Thread.Sleep(5000); bool requestCompletedInFiveSeconds = iar.IsCompleted; // When you're ready, remember to call EndDoWork to tidy up client.EndDoWork(iar); client.Close(); 

If this sounds like it might help, read the asynchronous pattern. This MSKB is extremely useful and shows several ways to write asynchronous code.

Perhaps the problem is that there is no way to cancel the WCF operation; you will need to write your own cancellation mechanism for this. For example, you cannot determine if a request is being executed (i.e. DoWork must be canceled), or if some kind of network or other machine latency is a delay.

0
source

All Articles