【问题标题】:Is it ok to bubble up the exception to the top of the stack?可以将异常冒泡到堆栈顶部吗?
【发布时间】:2011-08-17 10:19:57
【问题描述】:

是否可以让异常冒泡到堆栈顶部而不是在每个方法中捕获它?.. 我们应该在任何情况下这样做吗? ..这种方法是否存在任何微妙的问题或副作用(例如丢失异常细节、堆栈跟踪或内部异常细节等)?


虽然我的问题很笼统,但目前我的情况如下:

我正在将现有的 WSE3 Web 服务移至 WCF,因此您的客户端是 WSE3 客户端。

我添加了一个行为,以便FaultException 将在 WCF 服务中发生时与客户端进行通信。当OperationContract 方法出现异常时,我会在客户端收到异常消息,没有任何问题。但是,每当它发生在OperationContracts 以外的方法中时,我都会以某种方式遇到与安全相关的问题。我无法确定确切的原因。

但是,作为一种解决方法,我想只从OperationContract 抛出异常,并让异常冒泡到OperationContract

【问题讨论】:

    标签: c# .net wcf exception-handling


    【解决方案1】:

    可以让异常冒泡而不是在每个方法中捕获它吗?

    不要在每个方法中捕捉异常! - 你应该捕获异常,如果你可以用它做一些有用的事情,例如:

    • 处理它(即不重新扔它)
    • 添加一些重要的上下文信息

    我维护的应用程序中每个网络都被 try-catch 块包围,我的字面意思是 每个 方法:

    public void DoSomething()
    {
        try
        {
            throw new NotImplementedException();
        }
        catch (Exception ex)
        {
            throw ExceptionHandler.CreateException(ex, "DoSomething");
        }
    }
    

    像这样捕获异常完全没有意义,除了使您的代码更难阅读和您的异常更难跟踪之外,什么也做不了。

    如果您的异常必须通过某个进程间边界(例如在 WCF 服务中),那么在您的异常暴露给世界的地方,您可能希望首先捕获、记录并重新抛出异常IPC 边界的兼容格式,以便您记录服务中的所有故障

    然而,在许多情况下,有一种替代机制专为此目的而设计 - WCF 具有IErrorHandler 接口,可以注册该接口以一致的方式捕获和记录所有未处理的异常,而无需在每个公开的 try-catch 块方法。

    【讨论】:

    • 在 Web 服务方法 (SOAP) 中,我执行的操作类似于您上面的代码:try { ... } catch ( Exception x ) { log(x); throw; } 在服务器上进行更多日志记录。我体验到,在 我的 端而不是 SOAP 服务的客户/用户端进行日志记录对我有很大帮助。
    • 感谢您的回答。但是会不会有任何副作用,比如丢失异常细节(不知何故)?或者你能想到的其他事情。
    • @CSharpLearner 如果您跨越 IPC 边界(例如通过 SOAP Web 服务),那么您可能想要添加 try-catch 块,但是许多框架提供了一种更灵活的方式来控制和记录抛出的异常,例如示例 WCF 提供了IErrorHandler 接口。这是你的想法吗?
    • 我已经实现了 IErrorHandler 并且仅使用该实现。但我仍然面临这个问题。我怀疑这是因为 WSE3 客户端(不是 WCF 客户端)与 WCF 服务通信。
    • @CSharpLearner 你有什么具体的例子吗?您可能希望使用 Fiddler 之类的东西来跟踪异常,以查看是否正在发送信息,从而确定问题出在客户端还是服务器。
    【解决方案2】:

    当然,这就是他们的目的。经验法则是捕捉异常,您可以在其中做出明智的尝试继续。因此,如果您遇到类似内存不足的情况,请让它冒泡并终止程序;如果您在迭代大量数据时得到除以零,请在可以继续下一个数据的地方捕获它。

    更新

    回答您的问题,不,所有细节(包括引发异常的堆栈跟踪)都与异常对象一起传播。

    看到的有时类似于

    highLevelFunction(){
       try {
         lowerLevelFunction();
       } catch (LowLevelException e){
         throw HighLevelException(e);
       }
    }
    

    异常链接。发生的情况是您有一些低级异常,例如“除以零”;你捕获它并引发一个新的异常,如“数据异常”,使其对调用highLevelFunction 的例程更有意义。

    (如果这不是完美的 C# 语法,请原谅我,我最近没有写太多。)

    【讨论】:

    • 感谢您的回答。但是会不会有任何副作用,比如丢失异常细节(不知何故)?或者你能想到的其他事情。
    【解决方案3】:

    如果您有一个完整的应用程序(GUI、业务、数据),让它冒泡到 UI 并在此处处理事件。这使您有机会同时向用户显示消息。它还将它捕获到动作原点(即当用户执行动作 X 时发生这种情况)。在每种方法中捕获它都太占用 CPU 并且没有必要,因为无论如何您都可以只记录堆栈跟踪以找到来源。如果您正在制作中间件应用程序,请尝试在界面处处理它或将其冒泡 - 取决于中间件的使用方式。

    【讨论】:

      猜你喜欢
      • 2022-01-09
      • 1970-01-01
      • 1970-01-01
      • 2015-07-03
      • 1970-01-01
      • 1970-01-01
      • 2015-02-02
      • 2011-05-17
      • 2020-09-10
      相关资源
      最近更新 更多