在ASP.NET MVC中,通過應用程序生命周期中的Application_Error事件可以捕獲到網站引發的所有未處理異常。本文作為學習筆記,記錄了使用Global.asax文件的Application_Error事件處理和捕獲全局異常的詳細步驟。
文章演示項目是使用vs2013編譯器編寫的,下載地址:GlobalExceptionHandle-By-Application_Error.zip。
在VS2013中新建一個MVC項目,這里要先關閉自定義錯誤,將Web.config配置文件中customErrors節點的mode設置為Off,注意大小寫:
<system.web> <customErrors mode="Off"></customErrors> <compilation debug="true" targetFramework="4.5"/> <httpRuntime targetFramework="4.5"/> </system.web>
在GlobalFilter全局過濾器中取消HandleErrorAttribute的注冊:
public class FilterConfig { public static void RegisterGlobalFilters(GlobalFilterCollection filters) { //filters.Add(new HandleErrorAttribute()); } }
打開Global.asax文件並添加Application_Error事件代碼:
protected void Application_Error(Object sender, EventArgs e) { Exception lastError = Server.GetLastError(); if (lastError != null) { //異常信息 string strExceptionMessage = string.Empty; //對HTTP 404做額外處理,其他錯誤全部當成500服務器錯誤 HttpException httpError = lastError as HttpException; if (httpError != null) { //獲取錯誤代碼 int httpCode = httpError.GetHttpCode(); strExceptionMessage = httpError.Message; if (httpCode == 400 || httpCode == 404) { Response.StatusCode = 404; //跳轉到指定的靜態404信息頁面,根據需求自己更改URL Response.WriteFile("~/HttpError/404.html"); Server.ClearError(); return; } } strExceptionMessage = lastError.Message; /*----------------------------------------------------- * 此處代碼可根據需求進行日志記錄,或者處理其他業務流程 * ---------------------------------------------------*/ /* * 跳轉到指定的http 500錯誤信息頁面 * 跳轉到靜態頁面一定要用Response.WriteFile方法 */ Response.StatusCode = 500; Response.WriteFile("~/HttpError/500.html"); //一定要調用Server.ClearError()否則會觸發錯誤詳情頁(就是黃頁) Server.ClearError(); Server.Transfer("~/HttpError/500.aspx"); } }
從上面的演示代碼可以看出,在Application_Error事件中可以通過Server.GetLastError()獲取Exception對象,並依據Exception對象獲取相關異常信息,包括HTTP錯誤碼、詳細的錯誤信息等等。在事件中可以根據需求編寫自己的業務代碼,比如記錄日志、跳轉到自定義的錯誤頁面等。
編寫Application_Error事件的代碼需要注意的地方
1、一定要取消GlobalFilter全局過濾器中HandleErrorAttribute的注冊,也要注意檢查項目中是否有其他全局過濾器對異常進行處理的,防止HTTP 500類型的服務器錯誤不會觸發Application_Error事件(其他類型錯誤依然可觸發)。
此外也可以關閉Web.config配置文件的自定義錯誤:<customErrors mode="Off"></customErrors>。因為一般情況下都是在Application_Error事件中處理要跳轉的自定義錯誤頁,這樣有利於設置HTTP錯誤代碼。
2、無論最終處理的流程如何,在流程結束或者響應輸出的地方,一定要調用Server.ClearError()方法清空異常,否則異常錯誤依然處於未被處理的狀態,如果customErrors mode="On",那么異常會被自定義錯誤模塊處理,除非本意就是要使用這種方式跳轉到錯誤頁。
如果已經關閉了自定義錯誤但又沒有調用ClearError方法,將會引發ASP.NET的詳細錯誤頁面(俗稱黃頁)。
3、如果要跳轉到靜態的自定義錯誤頁面中,請使用Response.WriteFile(string filename)方法,最后設置下HTTP狀態碼,比如下面的代碼:
//跳轉到指定的靜態404信息頁面,根據需求自己更改URL Response.WriteFile("~/HttpError/404.html"); Server.ClearError();
4、如果想要使用Server.Transfer(string path)方法跳轉到自定義的錯誤頁面,這里有兩點需要注意:
第一點、一定不能設置HTTP狀態碼(Response.StatusCode),否則會引發IIS錯誤,無論是跳轉到靜態還是動態頁面中。例如下列代碼:
//Response.StatusCode = 500; //Server.Transfer("~/HttpError/500.html"); //Server.Transfer("~/HttpError/500.aspx");
第二點、Server.Transfer方法對路由地址不兼容,會引發錯誤,下面代碼使用路由會引發另一個異常:
Server.Transfer("~/Home/Index");
使用應用程序全局錯誤的一些優勢:
第一點就是兼容性好,Web Form和MVC中都可以通用,如果舊的Web Form項目中是使用Application_Error處理全局異常,那么在新的MVC項目就可以很容易移植過來!此外靈活性也比較高,相比ASP.NET自帶的自定義錯誤以及MVC的HandleError特性,可以更加自由的編寫靈活的業務代碼。
另外可以根據需求設定HTTP錯誤碼,這方面也是考慮到一個SEO的問題,畢竟ASP.NET的自定義錯誤機智是使用302重寫跳轉,並不有利於SEO。雖然customErrors節點的redirectMode屬性可以設置為"ResponseRewrite"(重寫),但是如果在跳轉的頁面上不設置HTTP錯誤碼,則HTTP狀態碼為200。
Application_Error處理網站異常的局限性
Application_Error事件無法處理已經被處理的異常,比如在try-catch捕捉的異常。此外由於是應用程序級別的事件,所以無法處理操作方法或者控制器級別的異常,暫時我也只想到這些局限,一般來說只要項目沒有什么特殊要求都可以使用此事件處理自定義異常。
出處:http://shiyousan.com/post/635813858052755170
歡迎轉載本文,本文版權歸作者所有,轉載請聲明出處或保留此段聲明。^_^請尊重他人勞動成果,共建美好的網絡環境。