我已经做了相当多的搜索,但却找不到解决方案或答案.我有一个我写的测试应用程序来显示“问题”. (我对这就是WCF工作的方式持开放态度,我无能为力.)
我的测试应用程序是一个简单的WCF服务和客户端与Visual Studio生成的代理.我将代理指向一个已启动但未运行该服务的远程计算机.这一点很重要.如果远程计算机根本没有运行,则WCF调用立即失败.
客户端应用程序创建客户端代理类的实例,启动新任务,然后尝试在服务接口上进行调用,这将阻止,因为另一端的服务不存在.后台任务休眠5秒钟,然后关闭代理.关闭代理时,我期待另一个线程立即出错,但事实并非如此.在进行初始呼叫大约20秒后,它就会出现故障.
这是我的客户端代码:
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); } } }
这是我的程序的输出:
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 ...
我想要完成的是让用户中断连接,以便他们可以根据需要进行调整,然后再试一次.正如您在输出中看到的那样,通道之后会从“打开”状态变为“已关闭”状态,但服务调用会一直处于阻塞状态,直到超时为止.我当然可以解决它,但似乎应该有一种方法来打断它.
这是客户端app.config:
<?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>
解决方法
如果使用异步操作生成代理类,则可能会获得更多里程,然后您的代码变得更加简单.
// 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();
如果这听起来有点帮助,请阅读异步模式. This MSKB非常有用,并展示了编写异步代码的几种方法.
您的问题实际上可能是无法取消正在进行的WCF操作;你必须为此编写自己的取消机制.例如,您将无法判断请求是否实际正在进行中(即:DoWork执行需要中止),或者是否存在某些网络或其他计算机延迟.