11

我有以下代码用于处理我的 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抛出的原因。

我想同时使用exceptionandexceptionWritingView并且两者都做一个例外,exceptionWritingView在顶部。

这将是:

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

但我无法InnerException在我的exception对象上设置属性。那么我怎么能做到这一点呢?

在“最好”的情况下,我可以创建一个新的Exceptionusing new Exception(exceptionWritingView.Message, exception),但我会失去部分StackTrace加分,我会失去任何本来可以拥有的InnerExceptionexceptionWritingView

反思是唯一的出路吗?用反射来做会有那么可怕吗?

4

4 回答 4

20

您可以使用System.AggregateException

例子:

WriteGracefulResponse(new AggregateException(new Exception[]
{
    exceptionWritingView,
    originalUnhandledException
}));
于 2012-08-12T06:40:06.913 回答
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();
}

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

于 2012-08-12T04:31:21.030 回答
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;
            }
        }
    }
}

编辑:您不能通过继承将设置器添加到 InnerException 或 StackTrace,但您可以添加单独的设置器属性 WritableStackTrace 并覆盖 StackTrace 以返回其值(技术上使其可设置)。

编写派生 Exception 类的另一种替代方法是编写一个与 AddPreviousException 非常相似的函数,除了它将深入到异常对象中,然后重新创建它,将要连接的异常传递给它的构造函数,然后按照你的方式工作吞下每个异常。

于 2012-08-12T12:13:00.583 回答
0

为什么要把事情复杂化?为什么不exception作为参数传递给WriteGracefulResponse方法?

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

您还应该重命名exceptionWritingView为以 结尾的东西exception,现在它会使认为这是一个视图的读者感到困惑。

于 2012-08-12T06:47:48.547 回答