【问题标题】:What is System.ServiceModel.Diagnostics.CallbackException and why can't I handle it?什么是 System.ServiceModel.Diagnostics.CallbackException,为什么我不能处理它?
【发布时间】:2011-01-16 04:50:18
【问题描述】:

在我的 WCF 客户端类中,我正在处理 Faulted() 事件,因此如果远程服务抛出异常并导致通道出现故障,我至少仍然可以正常关闭它。这是我的代码:

protected void RemoteDataRetriever_Faulted(object sender, EventArgs e)
{
    (sender as ICommunicationObject).Abort();
    this.Dispose();
    throw new ChannelTerminatedException("The remote service threw an unhandled exception and as a result the channel has been closed.");
}

所以我期望客户端可以处理我手动抛出的ChannelTerminatedException 并向用户发送消息等。相反,我的异常被包裹在System.ServiceModel.Diagnostics.CallbackException 中。好的。除了这里有一个问题:ServiceModel 库中不存在此 CallbackException,而且我似乎无法处理它,除非作为通用的 Exception,这对我的单元测试没有好处。这到底是怎么回事?我可以以某种方式禁用它并抛出我最初想要的异常吗?

【问题讨论】:

  • 既然你自己抛出异常,你可以使用另一个没有被包装的异常吗?我在想一些不会暴露你在它下面使用 WCF 的事实......
  • 没有骰子。我将 ChannelTerminatedException 更改为 StackOverflowException ;-) 它仍然被包裹在那个烦人的 CallbackException 中(我抛出的最终是内部异常)。然后它给出了令人讨厌的消息:“用户回调引发了异常。检查异常堆栈和内部异常以确定失败的回调。”是的,我知道回调引发了异常!是我扔的!我将做更多的研究,看看是否有一个 WCF 标志/参数可以用来禁用此行为。

标签: .net wcf exception exception-handling faulted


【解决方案1】:

事实证明,System.ServiceModel.Diagnostics.CallbackException 是一个内部类,填充在一个名为“%SystemRoot%\Microsoft.net\Framework\v3.0\Windows Communication Foundation\SMDiagnostics.dll”的鲜为人知的程序集中,它本身只包含内部类。好吧,这很糟糕,因为这意味着我们永远无法捕获该异常。但是,我能够找到实例化上述异常的类/方法 (System.ServiceModel.Diagnostics.ExceptionUtility.ThrowHelperCallback(Exception innerException)) 并发现它是由 CommunicationObject 内的虚拟方法 OnFaulted() 调用的。所以理论上任何派生自 CommunicationObject 的类(对不起ClientBase<T>)都可以覆盖该方法并告诉它不要调用 ThrowHelperCallback()。这意味着唯一可行的候选者是派生自ChannelFactoryBase<T> 的类。理论上,我可以继续实现我自己的自定义通道工厂,它可以抑制烦人的 CallbackException,但目前工作量太大,所以我想我只需要处理它。

编辑:@Jeremy - 如果我检查通过线路返回的 SOAP 信封,我发现它给了我一个一般错误,正如预期的那样,这表明 CallbackException 没有被序列化,因此没有在服务器。

<s:Body>
    <s:Fault>
        <s:Code>
            <s:Value>s:Receiver</s:Value>
            <s:Subcode>
                <s:Value xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:InternalServiceFault</s:Value>
            </s:Subcode>
        </s:Code>
        <s:Reason>
            <s:Text xml:lang="en-US">The server was unable to process the request due to an internal error.  For more information about the error, either turn on IncludeExceptionDetailInFaults (either from ServiceBehaviorAttribute or from the &lt;serviceDebug&gt; configuration behavior) on the server in order to send the exception information back to the client, or turn on tracing as per the Microsoft .NET Framework 3.0 SDK documentation and inspect the server trace logs.</s:Text>
        </s:Reason>
    </s:Fault>
</s:Body>

【讨论】:

  • 我认为我没有澄清客户端上生成 CallbackException 作为对主机返回的未处理异常的响应。我的主要观点是一般错误应该在服务器端处理,这样客户端(很可能由其他人用另一种语言构建)就不必这样做。
  • 好的,+1 给你的答案。作为回复,我使用 FaultContracts 发送最常见的异常,以便在客户端优雅地处理,但理想情况下,更严重和意外的异常将在 Faulted 事件中处理。这就是为什么我对 MS 有点不高兴,因为他们窃取了我试图抛出的异常并将其包装在他们内部的类中。然而,在为少数 MS 框架开发之后,我现在知道这只是课程的标准。
  • 如何处理异常是每个人都有不同的做事方式之一,但我同意抛出一个不可访问的异常是没有意义的,即使抛出它的方法是有意的被覆盖。至少将其包装在公共类型中以便可以处理。
【解决方案2】:

您看到System.ServiceModel.Diagnostics.CallbackException 是因为服务器上发生了异常。由于异常发生在客户端应用程序的域之外,它可能属于客户端无权访问的类型。回调机制通过生成您所看到的 CallbackException 来处理此问题。这类似于在访问静态成员时发生未处理的异常时抛出的System.TypeInitializationException。如果您尝试优雅地处理此问题,您可能希望在服务器端处理异常并关闭套接字,这随后会在客户端触发可以处理的异常。

【讨论】:

  • 我认为我的措辞有点含糊。我已经将答案编辑得更清楚了。
猜你喜欢
  • 1970-01-01
  • 2021-04-15
  • 2011-06-04
  • 2013-07-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-08
相关资源
最近更新 更多