WCF跟踪。如何获取关闭连接的确切原因?

11

在我的WCF服务中,当尝试传输大数据时,我经常会收到以下错误:The underlying connection was closed: The connection was closed unexpectedly

我想知道是什么具体原因导致了这个错误,所以我设置了WCF跟踪并可以读取traces.svclog文件。

问题在于,我可以在这个文件中看到很多关于流程的信息,我可以看到异常发生的确切时间,但我无法看到确切的原因。是否是由于MaxReceivedMessageSize等原因引起的?

是这样吗,traces.svclog无法包含这样的信息,还是我做错了什么?

如何获取这样的信息?

编辑(添加):

来自我的服务器端app.config:

    <system.serviceModel>
    <bindings>
        <basicHttpBinding>
            <binding name="NAVBinding_ICustomer_Service"
                closeTimeout="01:50:00"
                openTimeout="01:50:00" receiveTimeout="01:50:00" sendTimeout="01:50:00"
                allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
                maxBufferSize="2147483647" maxBufferPoolSize="2147483647"
                maxReceivedMessageSize="2147483647" messageEncoding="Text"
                textEncoding="utf-8" transferMode="Buffered" useDefaultWebProxy="true">
                <readerQuotas maxDepth="2147483647" maxStringContentLength="2147483647"
                    maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
                <security mode="None">
                    <transport clientCredentialType="None" proxyCredentialType="None"
                        realm="" />
                    <message clientCredentialType="UserName" algorithmSuite="Default" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <services>
        <service name = "Customer_Service"  behaviorConfiguration="returnFaults">
            <endpoint name="NAVBinding_ICustomer_Service"
               address  = "http://localhost:8000/nav/customer"
               binding  = "basicHttpBinding"
               bindingConfiguration= "NAVBinding_ICustomer_Service"
               contract = "NAVServiceReference.ICustomer_Service"/>
        </service>
    </services>
    <behaviors>
        <serviceBehaviors>
            <behavior name="returnFaults" >
                <serviceDebug includeExceptionDetailInFaults="true" />
                <serviceMetadata httpGetEnabled="true" />
            </behavior>
        </serviceBehaviors>
    </behaviors>
 </system.serviceModel>

编辑(新增):

将WCF服务从“黑盒子”转变为易于故障排除的服务,以便告知某些情况无法按预期执行的原因是什么,哪种方法是正确且最佳的?您使用哪些工具和技术来排除WCF服务问题?


你的跟踪日志中应该记录了你正在尝试发送的文件大小是多少? - Tony The Lion
文件的大小约为8MB。实际上,它是通过XML流传输的数据库表数据的大小,因此我不知道数据流的最终确切大小,包括可能的XML标记信息。但肯定比默认的MaxReceivedMessageSize参数的65536大。 - rem
你能展示一下服务器的 app.config 文件吗(即 <system.serviceModel> 部分)?你是否使用 WCF 流传输(例如,返回类型为 Stream 的方法),还是缓冲传输(默认)? - marc_s
我已将服务器app.config添加到我的问题内容中。关于WCF流 - 我的服务契约方法中没有一个返回类型为“Stream”(它们大多具有“someArray []”返回类型)。 - rem
对我来说,秘诀是在客户端上进行跟踪... - Benjol
6个回答

33

除忽略其他人已经回答过的有关maxRequestLength的问题外,我将回答您最初关于如何排除WCF故障的问题。

如果您已经在使用服务跟踪查看器(我无法从问题中确定您是否只是手动查看),则可能并非所有详细信息都记录在文件中。

当我想要真正深入时,我会启用所有消息日志记录的日志参数。(这将生成一些大型的服务日志,所以不要让其一直开启)

 <system.serviceModel>
  <diagnostics>
   <messageLogging logEntireMessage="true" logMalformedMessages="true" logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" maxMessagesToLog="-1" />
  </diagnostics>
 </system.serviceModel>
如果你没有使用Microsoft Service Trace Viewer,我建议你试试。它提供了所有我需要的信息来追踪那些棘手的消息握手、消息大小异常等问题。这里是一个MSDN参考文献,可以帮助你入门。http://msdn.microsoft.com/en-us/library/aa751795.aspx 潜在问题的跟踪交互会在左侧以黄色突出显示,并且顶部右侧的详细面板通常会以红色突出显示异常服务事件。有时,由于内部错误通过服务堆栈级联,您将遇到多个问题,但您可以在跟踪查看器中查看所有这些内容。 Troubleshooting Using the Service Trace Viewer 如果在服务器“服务日志”中什么也没有出现,则可能完全是客户端问题-理论上,在任何消息实际到达Web服务端之前,您就已经超过了某些客户端安全参数(消息大小等)-但是客户端问题通常更容易跟踪,因为你只需要担心在客户端编辑配置文件(即不是由客户端和服务器设置之间的任何交互引起的)。

+1 对于屏幕截图和服务跟踪查看器的引用,这基本上非常棒。 - Jeremy McGee

8
我已经花了2天多的时间来查找为什么在调用返回更多数据的方法时会出现“基础连接被关闭:连接意外关闭”的错误,而不是返回较少数据时的情况(即,仅返回较小的数据集时正常工作)。
我的错误信息略有不同(可能由于框架差异),但我想分享我发现的原因。首先,我想说的是,虽然跟踪和增加配置文件中某些内容的大小可能有助于跟踪WCF错误,但这些东西对我确定错误的真正原因没有任何帮助。
通过仅查看抛出的异常和上面的链,我可以看到以下根本错误: “现有的连接被远程主机强制关闭” - 这是一个System.Net.Sockets.SocketException
然后沿着调用链向上看:
“无法从传输连接读取数据:现有的连接被远程主机强制关闭。” - 一个System.IO.IOException,然后
“基础连接被关闭:接收时发生了意外错误。” - 一个System.Net.WebException,最后捕获的异常消息,
“在接收HTTP响应时发生错误。这可能是由于服务端点绑定未使用HTTP协议引起的。这也可能是由于服务器中止了HTTP请求上下文(可能是由于服务关闭引起的)。请参阅服务器日志以获取更多详细信息。” - 一个System.ServiceModel.CommunicationException
启用跟踪,然后使用TraceViewer查看跟踪日志确实使这更容易看到,但从未告诉我“现有的连接被远程主机强制关闭”错误的真正原因。
在我的情况下,我的WCF服务托管在IIS6上,只有当我联系负责这些服务器的机构支持并要求他们查看系统事件日志时,我立即看到了答案 - 一个System.OutOfMemoryException!
我的WCF服务运行在分配的200MB RAM中,而我的方法正在消耗更多。 我查看了我的方法,并最终发现应将一块代码放在其下方/下方的块(循环)之外。 . ..所以我的方法中生成了指数类型的集合。
希望这可以帮助其他人。

2
回答您的问题,如何创建一个易于故障排除的WCF服务。一种方法是尽量减少潜在错误的数量,这样在故障排除时就有更少的东西需要查看。
错误的两个主要来源:
- 配置错误 - WCF服务抛出的异常
配置错误通常是由于客户端和服务之间不匹配引起的。为了避免这种情况,请将所有可能的配置都放在BindingConfiguration中,并在客户端和服务器上复制和使用它。我认为这实际上是您的问题所在,您正在更新服务web.config,其中某些内容也需要在客户端配置中。例如最大大小或在一个中具有缓冲,在另一个中具有流式传输。
服务抛出的错误应该作为FaultException抛出,并在合同中定义为FaultContract
对于其余的错误,您需要查看trace.svclog文件,就像其他帖子中描述的那样。您还需要查看事件日志和IIS日志,因为调用可能会在到达WCF服务之前被阻止。

1

尝试设置maxRequestLength属性:

<system.web>
    <httpRuntime maxRequestLength="2147483647" />
</system.web>

我已经尝试过(只是将您的代码添加到服务器app.config中),但在发生的事情方面没有明显的变化。 - rem
你能否上传 traces.svclog 文件到某个地方,以便我们查看吗? - Darin Dimitrov

1
对于仍在遇到这个问题的人-和往常一样,以上讨论中还有一些绝对关键的事情被省略了,如果没有这些内容,就没有找到答案的希望。以下是我花了3个小时在网上查找才找到的内容。
回顾一下: 首先,我在使用Silverlight服务的WCF时遇到了可怕的未找到错误。不,这不是因为服务没有找到。我能够清楚地跟踪调用的服务方法直到最后,包括返回。然后客户端在异步调用的结束部分得到了一个异常。没有解释。与绑定等无关。
然后我发现像这样的论坛留言,关于使用跟踪查看器。结果我已经配置好了,但没有得到任何跟踪(所以我认为我的服务必须没问题,特别是因为我可以跟踪)。错了,宝贝。然后我发现另一条消息说,一个鲜为人知的事实是,如果你设置了一个跟踪侦听器来写入"C:\logs\mylog",你必须先手动创建C:\logs。它不会为你做这件事。

好的,现在我获取了日志并将其在TraceViewer中打开。结果我收到了一个关于未终止字符串的"错误消息"。三十分钟后,我发现另一条消息说,哦,每个人都知道你必须先结束本地开发服务器才能清除最后的消息。你知道,那些实际告诉你出了什么问题的消息?

现在我看到了真正的错误,并查看了每一个错误:抛出异常、RequestContext被中止以及通过http发送响应消息失败。只有第一个错误很重要。当然,在查看下面的窗格时,它根本没有给我任何有用的信息,只是说有一个序列化错误。嗯,“在哪里”会很好。

在绝望中,我突然注意到下面的窗格旁边有一个小小的XML选项卡,就在“格式化”选项卡旁边。当我点击它时,对于我的ThrowingAnException消息,它就在那里——一个庞大的转储,带有高度具体的消息,让我直接找到了问题所在:

System.ServiceModel.CommunicationException,System.ServiceModel,版本=4.0.0.0,Culture=neutral,PublicKeyToken=b77a5c561934e089 尝试序列化参数:GetTimecardsWithAlertsResult时出错。InnerException消息是“枚举值'0'对于类型'Timeclock.Web.ShiftManager.AlertType'无效,不能进行序列化。请确保如果该类型具有DataContractAttribute属性,则必要的枚举值存在并标记有EnumMemberAttribute属性。”。 有关更多详细信息,请参见InnerException。

问题是我没有初始化类的基于枚举的成员,因此它为0,这不是我的允许枚举值之一。非常容易解决。

很明显,对于微软来说,非常简单的检测,考虑到他们成功地将大量信息隐藏了3个小时。

这里有一个想法,微软——你怎么不提供一种捕获这些错误和非常重要的异常消息服务器端的方法呢?或者让它们完全通过Silverlight客户端?你知道,为了方便查看发生了什么,所以我可以在3秒钟内修复这个简单的问题,而不是花费3个小时向我的客户收取毫无用处的费用?

哦,我知道了。这很难因为它是一个异步调用超过http,并且不友好的互联网使它让人头痛。但你知道吗?你是微软。你拥有无限的时间和金钱。而且你影响着数百万人。当你像你在成千上万的场景中那样胡闹时,你会影响全球数十万开发人员。

在StackOverflow上看看。看看全球有多少聪明人试图编写有用的重要软件,他们并没有沉浸在上述的细枝末节中,因为你知道的,他们有真正的工作要做。

将我在这个愚蠢问题上花费的3个小时乘以数以万计的开发人员的30-40次类似的问题,一年中你就会看到你造成了什么灾难。说“这就是我们赚大钱的原因”没关系,但想想如果每次我们转身都不必跳进你挖给我们的3小时的困境,我们所有人都可以在世界上完成实际的好工作。

微软,你对编程、商业和人性都是有害的。我不在乎有多少台计算机运行你的软件,你需要做得更好。请开始表现得像是你理解了你每天在世界上滥用辛勤工作的人民有多少,无论在哪个国家。如果你像重视做正确的事情一样行事,你可以让这个世界变得更好。

蒂姆·约翰逊


1
你知道,在这里发牢骚不太合适,但我必须承认我有同样的感受... 我不记得我在 WCF 跟踪上浪费了多少个小时。只是因为枚举中没有零这个名称,就必须学习如何配置一个 XML 文件来生成日志以在图形工具中打开吗?直接给我一个异常就好了! - Eldritch Conundrum

0

你应该在客户端得到一个特定的通信异常。 我认为你所描述的这个异常是在尝试重用已经出错的客户端后抛出的异常。

请尝试以下操作:

  1. 在服务器端配置文件中设置includeExceptionDetailInFaults="true"
  2. 当你使用客户端时,不要使用'using pattern'。查看this文章。

我认为你不需要跟踪。尝试上述方法,你将能够看到确切的通信错误。

哦,顺便问一下,你的客户端是Silverlight应用程序吗? 如果是的话,那就有点复杂了...查看this文章。


不,它不是Silverlight,它是WPF应用程序。 - rem
事实上,我已经在我的服务器app.config文件中包含了includeExceptionDetailInFaults="true",但它并没有帮助我获取断开连接的原因。也许我设置不正确。 - rem

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接