代码之家  ›  专栏  ›  技术社区  ›  bevacqua

如何连接两个异常?

  •  16
  • bevacqua  · 技术社区  · 14 年前

    我有以下代码用于处理web应用程序中的异常:

    application.Response.Clear();
    application.Response.Status = Constants.HttpServerError;
    application.Response.TrySkipIisCustomErrors = true;
    
    LogApplicationException(application.Response, exception);
    try
    {
        WriteViewResponse(exception);
    }
    // now we're in trouble. lets be as graceful as possible.
    catch (Exception exceptionWritingView)
    {
        // Exception wrapper = ??
        WriteGracefulResponse(exceptionWritingView);
    }
    finally
    {
        application.Server.ClearError();
    }
    

    这里的问题是,如果在尝试将响应呈现为 ViewResult ,我正在“抑制”原始异常(在 View 无论如何),并仅显示导致错误的原因 流程分析 投掷。

    两样我都要 exception exceptionWritingView 并对两者都破例 例外写入视图 在顶部。

    这将是:

    exceptionWritingView
        -> inner exceptions of exceptionWritingView
                -> original exception that raised the unhandled exception handler
                           -> its inner exceptions
    

    但我不能设置 InnerException 我的财产 例外 对象那么我该如何做到这一点呢?

    “最好”我可以创造一个新的 Exception 使用 new Exception(exceptionWritingView.Message, exception) ,但我会失去 StackTrace 再加上我会失去任何 内部异常 是的 例外写入视图 本来可以的。

    反思是唯一的出路吗?反思一下会有那么可怕吗?

    4 回复  |  直到 14 年前
        1
  •  25
  •   Steven    4 年前

    您可以使用 System.AggregateException

    示例:

    WriteGracefulResponse(new AggregateException(new Exception[]
    {
        exceptionWritingView,
        originalUnhandledException
    }));
    
        2
  •  0
  •   Jeff Vanzella    14 年前

    您不是通过setter设置内部异常,而是通过构造函数设置内部异常。

    application.Response.Clear();
    application.Response.Status = Constants.HttpServerError;
    application.Response.TrySkipIisCustomErrors = true;
    
    LogApplicationException(application.Response, exception);
    try
    {
        WriteViewResponse(exception);
    }
    // now we're in trouble. lets be as graceful as possible.
    catch (Exception exceptionWritingView)
    {
        // Example on how to nest exceptions.
        throw MyException("Error message", exceptionWritingView);
    }
    finally
    {
        application.Server.ClearError();
    }
    

    堆栈跟踪将保存在内部异常中。

        3
  •  0
  •   Karel Frajták    14 年前

    为什么要把事情搞复杂?为什么不通过 exception 作为中的参数 WriteGracefulResponse 方法

    ...
    // now we're in trouble. lets be as graceful as possible. 
    catch (Exception exceptionWritingView) 
    { 
       // Exception wrapper = ?? 
       WriteGracefulResponse(exception, exceptionWritingView); 
    } 
    

    您还应该重命名 exceptionWritingView 以…结尾 例外 ,现在它混淆了那些认为这是一种观点的读者。

        4
  •  0
  •   Despertar    14 年前

    正如你所说,最大的问题是Exception只提供getter,这限制了你的能力。要解决这个问题,你可以从Exception继承,使其属性可设置。在我的示例类中,您可以初始化FlexibleException,它通过一个常规异常递归,基本上是对其进行复制,但复制是可设置的。然后,要添加上一个异常,它可以沿着阶梯向下移动,直到找到末端并固定到它上,将两个异常连接起来。我从来没有用过这样的东西,所以这只是我写的东西,它可能有一些错误,但我相信它实现了你想要做的。

    application.Response.Clear();
    application.Response.Status = Constants.HttpServerError;
    application.Response.TrySkipIisCustomErrors = true;
    
    LogApplicationException(application.Response, exception);
    try
    {
        WriteViewResponse(exception);
    }
    
    catch (Exception exceptionWritingView)
    {
        FlexibleException lastException = new FlexibleException(exceptionWritingView);
        lastException.AddPreviousException(exception);
        WriteGracefulResponse(lastException);
    }
    finally
    {
        application.Server.ClearError();
    }
    

    public class FlexibleException : Exception
    {
        public FlexibleException(Exception e)
        {
            this.InnerException = e.InnerException != null ? new FlexibleException(e.InnerException) : null;
            this.StackTrace = e.StackTrace;
        }
    
        public FlexibleException InnerException { get; set; }
    
        public string StackTrace { get; set; }
    
        public void AddPreviousException(Exception e)
        {
                FlexibleException prevException = new FlexibleException(e);
            FlexibleException nextException = this;
    
            while (true)
            {
                if (nextException.InnerException != null)
                {
                   nextException = nextException.InnerException;
                   continue;
                }
                else
                {
                   nextException = prevException;
                   break;
                }
            }
        }
    }
    

    编辑:您不能通过继承将setter添加到InnerException或StackTrace,但您可以添加一个单独的setter属性WritableStackTrace并重写StackTraces以返回其值(从技术上讲,使其可设置)。

    编写派生Exception类的另一种选择是编写一个与AddPreviousException非常相似的函数,只是它将深入到异常对象中,然后重新创建它,将要连接的异常传递到其构造函数,然后逐步吞下每个异常。