top
Loading...
在ASP.NET2.0中實現異常管理
介紹

在任何應用系統開發中,異常管理對開發人員來說都是一個關鍵領域。作為一個開發人員,你應該采用一種合適的、能讓你編寫健壯且高質量代碼的異常管理策略。如果使用得當,異常管理將是一個很強大的概念而且使你的開發工作變的很容易。然而,一個不合適的異常處理將會使你的應用系統性能降低。

在你鉆研這些之前,要先搞清楚異常管理是什么,這點很重要。一般來說異常就表示“打破系統預定的假設”。“異常”和“錯誤”是不一樣的,為了解釋清楚,我們來看兩個例子:

示例一

我們假設你試圖向一個文件寫入數據,而你的應用程序也認為這個文件在正確的路徑上。如果不在,就會拋出一個異常。而話說回來,如果你的職責是跟蹤此文件,那么代碼里還有(找不到文件的)異常那將是一個不好的編碼習慣,這種情況應該被校驗代碼處理(而不是異常)。

示例二

再讓我們假設一個一般的ASP.NET程序中,你正試圖更新數據庫中所有必需的字段。你的應用程序認為此數據庫連接可用,假設實際上這個連接是不可用的……拋出異常是一個解決方案。而我們又把話說回來,如果更新數據庫的必填字段時出現有幾個值為空的字段,那拋出異常就沒有必要了,這些處理應該由校驗代碼完成。

如何處理異常

作為一個開發人員,你應該感受到通過try, catch, finally塊來構建一個結構化異常處理機制的優點。.NET框架提供了一大堆異常處理層次來處理不同種類的異常。所有的異常都繼承自Exception(基類)。你可以通過繼承來實現自定義錯誤處理以擴展異常處理機制。不幸的是,很多開發人員都誤用了這種架構能力。一個隨時要記著的事是當一個異常發生在運行時時(這個架構)應該如何運作?一般有以下三種情況:

忽略異常,讓它在調用棧里上升而被其它的catch塊捕獲。

捕獲異常,同時為你的應用程序執行必要的動作,如果你不想再次在異常中拋出異常的話。

捕獲異常,并用其它異常覆蓋它。這樣和你的應用程序有更密切的關系。異常覆蓋是為了避免打破(架構中的)抽象層次。你可以通過你拋出的異常的InnerException屬性指定原異常是什么,這樣就可以把你現有的異常用一個新的異常來覆蓋了(更與你系統有關的)。為了了解異常覆蓋,讓我們來看一個能引起IOException異常的方法,你可以在應用級別使用LoadingException 或 FailtoLoadInfoException來覆蓋原有的IOException異常,這樣比把底層的IOException給用戶看到要來的好些。

一個應用程序的異常處理框架應該有以下幾種(要求):

探測異常;

執行代碼清除;
內部異常覆蓋;
內部異常替換;
記錄并報告錯誤信息;
建立能被外部監視的事件以幫助系統操作;

在開始你應該建立一個一致的,健壯的異常管理架構,在你所有的系統中應該很好的封裝并抽象其記錄和報告等的細節。

好的習慣

以下列出一些不錯的提示/建議供你在(設計)異常處理(時)參考:

拋出異常要不小的代價。所以,你應該盡可能地在“異常情況”下進行異常處理,不要去控制正規邏輯流程。比如,以下代碼:

void EmpExits(string EmpId)
{
// search for employee
if(dr.Read(EmpId) == 0) // no record found
{
throw(new Exception("Emp Not found"));
}
}

應該用以下代碼:

bool EmpExits(string EmpId)
{
// search for employee
if(dr.Read(EmpId) == 0) // no record found
{
return false;
}
}

避免在循環中捕獲異常,如果實在是要捕獲,那把整個循環都放在try/catch塊里。

采用標準try/catch/finally異常處理方式進行處理,這在托管代碼里是被推薦的。最后的Finally塊確保異常事件中的資源都被釋放掉了。

比如:

SqlConnection conn = new SqlConnection("");
try
{
conn.Open();
// some operation
// some additional operations
}
catch(Exception ex)
{
// handle the exception
}
finally
{
if (conn != null && conn.State == ConnectionState.Open)
conn.Close(); // closing the connection
}

盡可能的用校驗代碼而避免使用異常。如果你知道一個可避免的條件可能會出現,那就讓它避免。比如,在執行任何操作以前,檢查空值(VB里是Nothing),這樣可以避免使用異常以及性能問題。

以下代碼:

double result = 0;
try
{
result = firstVal/secondVal;
}
catch(System.Exception e)
{
// handling the zero divided exception
}

應該替換成:

double result = 0;
if(secondVal != null && secondVal > 0)
{
result = firstVal/secondVal;
}
else
{
result = System.Double.NaN;
}

不要為沒有必要的情況(原文:reasons)拋出異常。再次拋出異常的開銷和實例化一個新異常的開銷一樣的大,同時再次拋出異常使程序調試工作增加難度。比如:

try
{
// Perform some operations ,in case of throw an exception…
}
catch (Exception e)
{
// Try to handle the exception with e
throw;
}

推薦的處理不同的錯誤的不同的方法是實現一系列的catch塊,這看起來好像沒有什么,但可以讓你的異常處理從特殊走向普通。比如捕獲一個和文件有關的異常明顯要比捕獲一個FileNotFoundException, DirectoryNotFoundException, SecurityException, IOException, UnauthorizedAccessException甚至最后的基類Exception,好的多。

ADO.NET 的錯誤應該通過 SqlException 或 OleDbException來處理。

使用ConnectionState屬性來檢查連接是否可用要比異常處理好的多。

要常使用Try/Finally,Finally提供了關閉連接的機會。Using語句可以達到同樣的效果。

用指定的處理程序來處理異常。在一些情況下如果你知道一些可能的異常那就用相應的異常處理類,比如:

try
{}
catch(SqlException sqlexp) // specific exception handler
{}
catch(Exception ex) // Generic exception handler
{}

你的異常處理架構應該可以探測異常并在內部將其覆蓋,(或是)使用其它異常將其替換,或是為監視系統而記錄和報告這些信息。

推薦大家使用 Microsoft's patterns & practices 團隊 提供的Exception Management Application Block。這是一個簡單且可擴展的框架用于記錄異常信息到事件文件中,你可以自定義它,把日志記錄到其它數據源中同時不影響你系統的代碼。Exception Management Application Block都是一些由patterns & practices團隊開發的很好的代碼,并且已經徹底地被Microsoft labs給測試過了。
作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗