c# – 如何中断因连接状态而阻塞的WCF代理,因为远程服务未运行

我已经做了相当多的搜索,但却找不到解决方案或答案.我有一个我写的测试应用程序来显示“问题”. (我对这就是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执行需要中止),或者是否存在某些网络或其他计算机延迟.

相关文章

在要实现单例模式的类当中添加如下代码:实例化的时候:frmC...
1、如果制作圆角窗体,窗体先继承DOTNETBAR的:public parti...
根据网上资料,自己很粗略的实现了一个winform搜索提示,但是...
近期在做DSOFramer这个控件,打算自己弄一个自定义控件来封装...
今天玩了一把WMI,查询了一下电脑的硬件信息,感觉很多代码都...
最近在研究WinWordControl这个控件,因为上级要求在系统里,...