如何连接两个异常?

时间:2012-08-12 03:34:10

标签: c# exception reflection exception-handling

我有以下代码用于处理我的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中),并且只显示导致错误ViewResult抛出。

我希望同时使用exceptionexceptionWritingView,并在两者之间设置一个例外,其中exceptionWritingView位于顶部。

这将是:

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

但我无法在InnerException对象上设置exception属性。那么我怎么能实现这个目标呢?

“最好”我可以使用Exception创建一个新的new Exception(exceptionWritingView.Message, exception),但我会丢失部分StackTrace加上我会失去任何InnerException exceptionWritingView可能有的。

反思是唯一的出路吗?用反射来做这件事会不会那么可怕?

4 个答案:

答案 0 :(得分:15)

您可以使用System.AggregateException

答案 1 :(得分:0)

您没有通过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();
}

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

答案 2 :(得分:0)

为什么让事情变得复杂?为什么不将exception作为参数传递给WriteGracefulResponse方法?

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

您还应该将exceptionWritingView重命名为以exception结尾的内容,现在它会让认为这是视图的读者感到困惑。

答案 3 :(得分:0)

正如您所说,最大的问题是例外仅提供吸气剂,这限制了您的能力。要解决此问题,您可以从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并覆盖StackTrace以返回它的值(技术上使其可设置)。

编写派生的Exception类的另一种方法是编写一个与AddPreviousException非常相似的函数,除了它将向下钻取到异常对象,然后重新创建它,将要连接的异常传递给它的构造函数,然后按照你的方式努力吞下每个例外。