[英]Exception Handling Application Block Exception Handler running in ASP.NET cannot call Response.End()
使用.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
。 這是唯一無法捕獲和忽略的異常類型。 rr! 誰能告訴我:
ThreadAbortException
? response.End()
的安全方法嗎? response.End()
之前檢測響應流是否“可結束”? 編輯-更多上下文
此代碼的設計目標是使添加EHAB樣式的錯誤處理到Web應用程序盡可能簡單。 我有一個自定義IHttpModule
,必須將其添加到web.config
文件中。 在模塊的Application_Error
事件中,它調用ExceptionPolicy.HandleException
。 必須將異常處理策略配置為調用上述的PageExceptionHandler
類。 整個過程僅涉及少量的XML配置,無需使用額外的文件,並且在使用的Web應用程序中無需使用任何額外的代碼行。
實際上,目前的代碼似乎可以正常工作。 但是,在某些情況下,需要在Web應用程序代碼中有一個明確的catch塊,該塊直接調用異常處理策略。 這種情況是無法正常工作的。 我想要一個可以在所有可能的調用方法下工作的解決方案。 我確實有一個印象,那就是如果不涉及EHAB,它會簡單得多,但是不幸的是,它在我們的所有代碼中都使用,並且提供了許多其他好處,我希望保留它。
編輯-測試結果
我創建了一個測試工具,以六種不同的方式來執行代碼:
HttpResponse
。 ExceptionPolicy.HandleException(ex, "Top Level")
。 ExceptionPolicy.HandleException(ex, "Top Level")
。 Page_Error
事件調用ExceptionPolicy.HandleException(ex, "Top Level")
。 Application_Error
事件調用ExceptionPolicy.HandleException(ex, "Top Level")
。 IHttpModule
類調用ExceptionPolicy.HandleException(ex, "Top Level")
。 編寫錯誤頁面標記后,每種方法的測試結果都沒有代碼可終止響應:
調用HttpContext.Current.ApplicationInstance.CompleteRequest
時每種方法的測試結果:
調用HttpContext.Current.Response.End
時每個方法的測試結果:
ExceptionHandlingException
。 調用HttpContext.Current.Response.End
時每個方法的測試結果,但包裝在try
... catch
塊中:
ThreadAbortException
,該異常由catch塊捕獲並吸收。 ThreadAbortException
和兩個ExceptionHandlingException
。 這是一種荒謬的行為。 :-(
看看ELMAH 。
關於ELMAH的文章和方法有很多,只是通過Google或必應搜索即可:-)
好處
+記錄幾乎所有內容
+電子郵件通知
+遠程查看錯誤
我建議使用它並重定向到默認錯誤頁面,如Ariel所述。
看一下這個微軟的解釋 。 它說它適用於ASP.Net 1.1,但我認為它仍適用於2.0。 基本上,您應該改為調用HttpContext.Current.ApplicationInstance.CompleteRequest
方法。
另外,我不確定為什么您無法捕獲ThreadAbortException
為什么您不能執行類似的操作
try {
// code
} catch (ThreadAbortException)
{
//do nothing
}
我處理ASP.net異常的方法始終是捕獲它,將其記錄下來,然后重定向到帶有一些標准錯誤消息的通用錯誤頁面(最終用戶將不在乎異常或堆棧跟蹤)。 您已經在處理程序之前將異常記錄到了策略中,所以也許您要做的就是將響應重定向到錯誤頁面,然后將BuildErrorPage邏輯移到該頁面。 您可以在querystring中傳遞handlingInstanceId。
嘗試在Global.asax中使用Application_Error來捕獲應用程序中任何頁面引發的任何未處理異常。
這可能會有所幫助: http : //msdn.microsoft.com/en-us/library/cyayh29d.aspx
特別是“您的清理代碼必須在catch子句或finally子句中,因為ThreadAbortException在系統中finally子句的末尾或在catch子句的末尾(如果沒有finally子句的情況)被系統拋出 。
您可以通過調用Thread .. ::。ResetAbort方法來防止系統拋出異常。 但是,僅當您自己的代碼導致ThreadAbortException時才應這樣做。 ”
請注意,Response.End和Response.Redirect在某些情況下可能會引發ThreadAbortException。
經過大量測試,我發現只有兩種方法可以正常工作。
解決方案1
完全不更改當前架構。 全局異常處理程序已按預期工作。 如果出於某種原因在代碼中需要顯式的catch塊(例如,在輸入表單上呈現驗證錯誤),那么我將告訴開發人員顯式調用Response.End
,例如
try {
// ...
} catch(Exception ex) {
if(ExceptionPolicy.HandleException(ex, "Top Level")) {
throw;
}
Response.End();
}
解決方案2
放棄嘗試覆蓋當前響應流並真正重定向到錯誤頁面的嘗試。 這對所有六個測試工具方法都可以正常工作。 下一個問題是找到一種方法,該方法需要對使用方項目進行最小的更改,並提取所有臟的細節。
步驟1-將占位符ErrorPage.ashx
文件添加到項目中,該文件僅包含對標准網頁處理程序類的引用,而沒有任何代碼后綴。
<%@ WebHandler Class="WebApplicationErrorPage" %>
第2步-使用會話密鑰傳遞所有必需的數據,重定向到PageExceptionHandler
類中的此頁面。
public Exception HandleException(Exception ex, Guid handlingInstanceID) {
HttpResponse response = HttpContext.Current.Response;
HttpSessionState session = HttpContext.Current.Session;
session["ErrorPageText"] = BuildErrorPage(ex, handlingInstanceID);
response.Redirect(errorPageUrl, false);
return ex;
}
第3步-使WebApplicationErrorPage
類成為僅寫入響應流的真正愚蠢的HTTP處理程序。
public class WebApplicationErrorPage : IHttpHandler, IReadOnlySessionState {
public bool IsReusable {
get {
return true;
}
}
public void ProcessRequest(HttpContext context) {
response.Clear();
response.ContentEncoding = Encoding.UTF8;
response.ContentType = "text/html";
response.Write((string) context.Session["ErrorPageText"]);
response.Flush();
}
}
結論
我認為我會堅持使用解決方案1,因為它不涉及斬波和更改現有體系結構(真正實現解決方案2的過程比上面的代碼片段要復雜得多)。 我將提交解決方案2以便在其他地方使用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.