異常的產生
在.net應用開發中,程式在運行時總會由於一些無法預料的、不合法的客觀條件產生問題,拋出異常。如:在類型轉換時,將一個非數字型字元轉換為整形時;一個參考型別未進行初始化我們卻調用它的方法或屬性時;io操作時資源未準備好時;資料庫操作時,db server無法訪問、或者sql出錯的時候,等等。
Asp.Net預設是怎麼處理異常的
在產生異常的時候如果我們沒有在自己的代碼中捕獲異常的話,應用程式會將異常資訊交給asp.net runtime, 將將會拋出一個HttpUnhandledException異常。就是這個異常報給了我們經常看到的黃頁資訊。當然,它不只是會報黃頁資訊而已,也可以根據配置中的資訊進行自訂異常頁面。
在webconfig設定檔中,<customErrors>該節點定義了HttpUnhandledException這個類的處理行為。不同的行為依賴於customErrors節點的mode屬性,共有下面三個屬性:
- On 對所有使用者展示自訂的錯誤頁面或者一個Runtime Error的黃頁,不包含錯誤的詳細資料
- Off 對所有訪問使用者暴露出詳細的錯誤資訊
- RemoteOnly 對非本機使用者暴露友好的錯誤資訊。
當我們自訂錯誤頁面的時候,可以這樣<customErrors mode="On" defaultRedirect="~/error.aspx" />定義一個錯誤頁面,也可以針對不同的異常類型指定不同的錯誤頁面,如:
<customErrors mode="On" defaultRedirect="error.aspx"> <error statusCode="404" redirect="404.aspx"/> <error statusCode="500" redirect="500.aspx"/> </customErrors>
這樣產生錯誤的時候就會根據不同的http碼跳轉到不同的頁面了。
另補充一句:
- HttpUnhandledException在針對異常根據不同的配置進行跳轉的時候是利用了
Response.Redirect()方法302跳轉。
- 真對一些靜態資源檔案的404情況不會被處理,這些是被iis直接處理的。
-
404了我該做些什麼
在發生404的時候有時是我們自己的站台連結寫的不正確,或者是來自一些其他網站的錯誤外鏈,那麼這個時候我們知道該連結來自哪裡很重要,所以在404後跳轉的頁面中我們最好將發生了什麼,在哪裡發生的告訴自己,並及時的處理。開始在想這個問題的時候我還覺得用urlref擷取不到錯誤頁面的來源。後來發現在 Response.Redirect()方法302跳轉的時候原始請求的一些資訊也是附帶過來的。所以打消了這個疑慮。這樣我們就可以在404異常處理頁面中記錄異常來源通知自己了。另外來自一些外站的錯誤連結,我們不能等待他們修改,我們可以做個錯誤連結的映射,在404處理頁面進行匹配處理。
404我們擷取到死連結的來源了,那麼我們如何擷取到詳細的錯誤資訊呢?
一個問題是,當我們定義了友好的錯誤頁面後,我們不能擷取到詳細的錯誤資訊。如:在1.aspx頁面發生了異常,將直接回跳轉到500.aspx頁面中,相當於2個請求,在新的請求當中(302跳轉),我們是沒有辦法擷取到前一個頁面的資訊的。下面看看針對這種情況我們如何處理它。
當一個未處理的異常拋給asp.net runtime時,會激發一個應用程式層級的例外狀況事件,通過在這個事件中擷取處理異常,我們可以記錄日誌,發郵件通知作者,用Server.Transfer()跳轉到自訂的錯誤頁面。Transfer不同於Redirect方法,它是在服務端的跳轉,會攜帶著上下文資訊,允許跳轉的頁面訪問這些資訊。;)
如何在應用程式層級的例外狀況事件中處理異常
HttpApplication應用程式類中包含了一系列的asp.net web 應用程式事件,當一個未被處理的異常發生時就會激發該類的Error事件。在該事件中我們可以通過Server.GetLastError()方法擷取發生的異常對象。之後就可以進行異常資訊的記錄、通知等操作了。在此處我們擷取的異常對象是HttpUnhandledException的執行個體,實際頁面發生的異常被該對象封裝在裡面了,可以通過InnerException屬性擷取到。
這樣我們就可以捕獲到應用程式發生的異常資訊並且記錄、發郵件啊之類的,之後在進行跳轉到自訂的有好錯誤頁面。
//擷取到頁面發生的異常對象 var error = Server.GetLastError(); if (error is HttpUnhandledException && error.InnerException != null) { error = error.InnerException; } try { //do something with error infomation } catch { } Server.Transfer("yourcustompage.aspx"); 用HttpModule方式處理例外狀況事件
為什麼要用HttpModule的方式?
這種方式提供了一種更靈活的處理方法,我們可以簡單的將dll放到bin目錄並且改幾句設定檔就可以加入我們的功能,非常靈活自由。
開源日誌庫:ELMAH
參考文摘:
http://www.4guysfromrolla.com/articles/090606-1.aspx
http://www.4guysfromrolla.com/articles/091306-1.aspx