WCF 的“使用”语句中的异常未正确关闭连接。如何关闭有故障的 WCF 客户端连接或有异常的连接?

Posted

技术标签:

【中文标题】WCF 的“使用”语句中的异常未正确关闭连接。如何关闭有故障的 WCF 客户端连接或有异常的连接?【英文标题】:Exception in "using" statement with WCF not closing connections properly. How does one close faulted WCF client connections or those with exceptions? 【发布时间】:2011-06-30 05:39:50 【问题描述】:

*** 上有几个关于关闭 WCF 连接的问题,但是排名最高的答案参考了这个博客:

http://marcgravell.blogspot.com/2008/11/dontdontuse-using.html

当我在服务器上设置断点并让客户端挂起超过一分钟时,我遇到了这种技术的问题。 (我故意创建一个超时异常)

问题是客户端似乎“挂起”,直到服务器完成处理。我的猜测是异常后一切都在清理。

关于TimeOutException,客户端的retry()逻辑似乎会一遍又一遍地向服务器重新提交查询,我可以看到服务器端调试器将请求排队然后同时执行每个排队的请求。我的代码不希望 WCF 以这种方式运行,这可能是我看到的数据损坏问题的原因。

这个解决方案并没有完全加起来。

什么是包罗万象的现代方式 处理故障和异常 在 WCF 代理中?

【问题讨论】:

【参考方案1】:

更新

诚然,这是一段平凡的代码。 I currently prefer this linked answer,并且在该代码中看不到任何可能导致问题的“黑客”。


这是微软推荐的处理 WCF 客户端调用的方法:

更多详情请见:Expected Exceptions

try

    ...
    double result = client.Add(value1, value2);
    ...
    client.Close();

catch (TimeoutException exception)

    Console.WriteLine("Got 0", exception.GetType());
    client.Abort();

catch (CommunicationException exception)

    Console.WriteLine("Got 0", exception.GetType());
    client.Abort();

其他信息 似乎有很多人在 WCF 上问这个问题,以至于微软甚至创建了一个专门的示例来演示如何处理异常:

c:\WF_WCF_Samples\WCF\Basic\Client\ExpectedExceptions\CS\client

下载示例: C# 或 VB

考虑到involving the using statement、(heated?) Internal discussions 和threads 在这个问题上存在很多问题,我不会浪费时间尝试成为代码牛仔并找到更清洁的方法。我将把它吸干,并为我的服务器应用程序以这种冗长(但受信任)的方式实现 WCF 客户端。

可选的附加故障捕获

许多异常源自CommunicationException,我认为大多数异常都不应该重试。我苦苦研究了 MSDN 上的每个异常,并找到了一个简短的可重试异常列表(除了上面的TimeOutException)。如果我错过了应该重试的异常,请告诉我。

Exception   mostRecentEx = null;
for(int i=0; i<5; i++)  // Attempt a maximum of 5 times 

    try
    
       ...
       double result = client.Add(value1, value2);
       ...
       client.Close();
    

    // The following is typically thrown on the client when a channel is terminated due to the server closing the connection.
    catch (ChannelTerminatedException cte)
    

      mostRecentEx = cte;
      secureSecretService.Abort();
        //  delay (backoff) and retry 
        Thread.Sleep(1000 * (i + 1)); 
    

    // The following is thrown when a remote endpoint could not be found or reached.  The endpoint may not be found or 
    // reachable because the remote endpoint is down, the remote endpoint is unreachable, or because the remote network is unreachable.
    catch (EndpointNotFoundException enfe)
    

      mostRecentEx = enfe;
     secureSecretService.Abort();
        //  delay (backoff) and retry 
        Thread.Sleep(1000 * (i + 1)); 
    

    // The following exception that is thrown when a server is too busy to accept a message.
    catch (ServerTooBusyException stbe)
    
      mostRecentEx = stbe;
        secureSecretService.Abort();

        //  delay (backoff) and retry 
        Thread.Sleep(1000 * (i + 1)); 
    

    catch(Exception ex)
     
         throw ex;  // rethrow any other exception not defined here
    

if (mostRecentEx != null) 

    throw new Exception("WCF call failed after 5 retries.", mostRecentEx );

【讨论】:

【参考方案2】:

Closing and Disposing a WCF Service

正如该帖子所暗示的,当没有异常时您关闭,当有错误时您中止。 Dispose 因此 Using 不应与 WCF 一起使用。

【讨论】:

基于该问题中的链接,在我看来,WCF 的东西不应该实现 IDisposable,而是应该有一个完全不同的清理架构。 @Chris Lively 确实,似乎每个人都试图拼凑出一个using 声明来反对微软的建议。 MSFT 的私人内部讨论显然希望生产应用程序具有特定的结构化异常处理。这将是冗长和烦人的,但假设我需要把它吸干。 我目前找不到链接,但我看到一个网站,有人使用 lambdas 以一种非常有趣的方式掩盖了这种行为。它使代码更加易于处理。如果我再次遇到它,我会发布链接。 bloggingabout.net/blogs/erwyn/archive/2006/12/09/… 这不是我想要的页面,但它是一个很好的模板类来帮助解决问题。它还链接到 MSFT 开发人员谈论它的 MSDN 论坛。

以上是关于WCF 的“使用”语句中的异常未正确关闭连接。如何关闭有故障的 WCF 客户端连接或有异常的连接?的主要内容,如果未能解决你的问题,请参考以下文章

WCF 超时太快和“连接意外关闭”异常

当连接未正确关闭时,为啥使用 WAL 模式的 SQLite 数据库中的数据会丢失?

学会WCF之试错法——客户端调用基础

C ++中的基本字符串连接未正确输出[关闭]

如何正确关闭客户端代理(现有连接被远程主机强行关闭)?

在 WCF 双工合同中检测客户端死亡