C# 由于远程服务未运行,如何中断处于连接状态的WCF代理
我已经做了大量的搜索,但没有找到解决方案或答案。我编写了一个测试应用程序来显示“问题”。(我接受这样的观点,即这就是WCF的工作方式,对此我无能为力。) 我的测试应用程序是一个简单的WCF服务和客户端,带有Visual Studio生成的代理。我将代理指向已启动但未运行服务的远程计算机。这一点很重要。如果远程计算机根本没有运行,WCF调用将立即失败 客户端应用程序创建客户端代理类的一个实例,启动一个新任务,然后尝试在服务接口上进行调用,该调用将被阻止,因为另一端的服务不存在。后台任务休眠5秒钟,然后关闭代理。我希望另一个线程在关闭代理时立即出错,但它没有。在发出初始呼叫大约20秒后,它就会出现故障 这是我的客户代码:C# 由于远程服务未运行,如何中断处于连接状态的WCF代理,c#,.net,wcf,C#,.net,Wcf,我已经做了大量的搜索,但没有找到解决方案或答案。我编写了一个测试应用程序来显示“问题”。(我接受这样的观点,即这就是WCF的工作方式,对此我无能为力。) 我的测试应用程序是一个简单的WCF服务和客户端,带有Visual Studio生成的代理。我将代理指向已启动但未运行服务的远程计算机。这一点很重要。如果远程计算机根本没有运行,WCF调用将立即失败 客户端应用程序创建客户端代理类的一个实例,启动一个新任务,然后尝试在服务接口上进行调用,该调用将被阻止,因为另一端的服务不存在。后台任务休眠5秒钟,
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 ...
我试图做到的是让用户中断连接,以便他们可以在必要时进行调整,然后重试。正如您在输出中所看到的,通道从“打开”状态变为“关闭”状态,但服务调用在超时之前一直处于阻塞状态。我当然可以解决这个问题,但似乎应该有办法打断它
以下是client 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();
如果这听起来可能有帮助,请仔细阅读异步模式。非常有用,并展示了几种编写异步代码的方法
您的问题实际上可能是无法取消正在进行的WCF操作;您必须为此编写自己的取消机制。例如,您无法判断请求是否实际正在进行(即,
DoWork
执行需要中止),或者某个网络或其他计算机延迟是否是延迟。绑定配置如何?Espeially receiveTimeout?将client app.config添加到原始问题…在任务操作中,尝试为Close()
调用传递显式超时:client.Close(TimeSpan.FromSeconds(2))
因此理论上它应该在最多2秒后关闭/引发异常我已经尝试将app.config中的closeTimeout更改为00:00:01,但对超时没有影响。我也会尝试在代码中显式地设置它。不幸的是,这也没有任何效果。我很快意识到,如果应用程序最初是用异步编写的,这不会是一个问题。不幸的是,我看到的是一个基于同步WCF调用(双向TCP)的重要代码库,修改框架和使用它的表示层需要大量的工作。这让我很难过,但我就是这样。提出我最初的问题,是否真的没有办法在超时之前中断连接?在本机套接字层,关闭套接字句柄将中断任何被阻止的调用。所以,我知道这是可能的。不幸的是,对你来说,我不这么认为。您需要异步调用DoWork
,以便控制。您是否可以翻转代码,以便生成一个任务来调用DoWork
,而不是生成一个任务来监视客户端?然后,您可以监视该任务,如果花费的时间太长,请将其终止。