我有以下代码用于处理我的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
抛出。
我希望同时使用exception
和exceptionWritingView
,并在两者之间设置一个例外,其中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
可能有的。
反思是唯一的出路吗?用反射来做这件事会不会那么可怕?
答案 0 :(得分:15)
答案 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非常相似的函数,除了它将向下钻取到异常对象,然后重新创建它,将要连接的异常传递给它的构造函数,然后按照你的方式努力吞下每个例外。