使用 .NET 3.5、ASP.NET、Enterprise Library 4.1 异常处理和日志记录块,我编写了一个自定义异常处理程序来显示标准错误页面,如下所示:
[ConfigurationElementType(typeof(CustomHandlerData))]
public class PageExceptionHandler : IExceptionHandler {
public PageExceptionHandler(NameValueCollection ignore) {
}
public Exception HandleException(Exception ex, Guid handlingInstanceID) {
HttpResponse response = HttpContext.Current.Response;
response.Clear();
response.ContentEncoding = Encoding.UTF8;
response.ContentType = "text/html";
response.Write(BuildErrorPage(ex, handlingInstanceID));
response.Flush();
//response.End(); // SOMETIMES DOES NOT WORK
return ex;
}
}
这是从异常处理策略中调用的,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<configSections>
<section name="exceptionHandling" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Configuration.ExceptionHandlingSettings, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</configSections>
<exceptionHandling>
<exceptionPolicies>
<add name="Top Level">
<exceptionTypes>
<add type="System.Exception, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
postHandlingAction="None" name="Exception">
<exceptionHandlers>
<add logCategory="General" eventId="0" severity="Error" title="Application Error"
formatterType="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.TextExceptionFormatter, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
priority="0" useDefaultLogger="false" type="Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging.LoggingExceptionHandler, Microsoft.Practices.EnterpriseLibrary.ExceptionHandling.Logging, Version=4.1.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
name="Log Full Details" />
<add type="PageExceptionHandler, Test, Culture=neutral, PublicKeyToken=null"
name="Display Error Page" />
</exceptionHandlers>
</add>
</exceptionTypes>
</add>
</exceptionPolicies>
</exceptionHandling>
</configuration>
一切正常,除了错误页面被合并到错误发生时显示的任何标记中。我以为添加response.End()
进入异常处理程序就可以解决这个问题。确实如此,但我随后观察到,有时 ASP.NET 会抛出一个ThreadAbortException
同时尝试结束响应流。这是唯一不能捕获和忽略的异常类型。咕噜!谁能告诉我:
- 在什么条件下 ASP.NET 会抛出
ThreadAbortException
当尝试结束响应流时?
- 有没有更安全的替代方案
response.End()
我可以用吗?
- 如果不是,有没有办法在调用之前检测响应流是否“可结束”
response.End()
?
编辑 - 更多上下文
此代码的设计目标是尽可能简单地向 Web 应用程序添加 EHAB 样式的错误处理。我有一个习惯IHttpModule
必须添加到web.config
文件。在模块的Application_Error
它调用的事件ExceptionPolicy.HandleException
。必须配置异常处理策略来调用PageExceptionHandler
上面描述的类。整个过程只涉及少量的 XML 配置,没有额外的文件,并且在使用的 Web 应用程序中没有额外的代码行。
事实上,目前的代码似乎运行良好。但是,在某些情况下,希望在 Web 应用程序代码中具有显式的 catch 块来直接调用异常处理策略。这种情况是不能正常工作的。我想要一个可以在所有可能的调用方法下工作的解决方案。我确实有这样的印象:如果不涉及 EHAB,事情会简单得多,但不幸的是,它在我们所有的代码中都使用,并且提供了许多其他好处,我宁愿保留它。
编辑 - 测试结果
我创建了一个测试工具,以六种不同的方式测试代码:
- 写入当前页面
HttpResponse
直接地。
- 构造异常对象并调用
ExceptionPolicy.HandleException(ex, "Top Level")
直接地。
- 抛出异常对象,捕获它并调用
ExceptionPolicy.HandleException(ex, "Top Level")
在 catch 块中。
- 抛出一个异常对象并让
Page_Error
事件调用ExceptionPolicy.HandleException(ex, "Top Level")
.
- 抛出一个异常对象并让
Application_Error
事件调用ExceptionPolicy.HandleException(ex, "Top Level")
.
- 抛出异常对象并让我的自定义
IHttpModule
班级电话ExceptionPolicy.HandleException(ex, "Top Level")
.
编写错误页面标记后,没有代码终止响应的每种方法的测试结果:
- 方法 1、2、3 - 错误页面标记与测试页面标记相结合。
- 方法 4、5、6 - 错误页面标记替换了测试页面标记(所需结果)。
每种方法的测试结果HttpContext.Current.ApplicationInstance.CompleteRequest
被称为:
- 方法 1、2、3 - 错误页面标记与测试页面标记相结合。
- 方法 4、5、6 - 错误页面标记替换了测试页面标记(所需结果)。
每种方法的测试结果HttpContext.Current.Response.End
被称为:
- 方法 1、5、6 - 错误页面标记替换了测试页面标记(所需结果)。
- 方法 2、3、4 - 错误页面标记替换了测试页面标记,但 EHAB 抛出
ExceptionHandlingException
twice.
每种方法的测试结果HttpContext.Current.Response.End
被称为,但包裹在try
... catch
block:
- 方法 5、6 - 错误页面标记替换了测试页面标记(所需结果)。
- 方法 1、3、4 - 错误页面标记替换了测试页面标记,但 ASP.NET 抛出
ThreadAbortException
它被捕获块捕获并吸收。
- 方法 2 - 错误页面标记替换了测试页面标记,但我得到了
ThreadAbortException
and also two ExceptionHandlingException
s.
这是一系列可笑的行为。 :-(