個人覺得異常處理對於程式員來說是最為熟悉的同時也是最難掌握的。說它熟 悉,因為僅僅就是try/catch/finally而已。說它難以掌握,則是因為很多開發人 員卻說不清楚try/catch/finally應該置於何處?什麼情況下需要對異常進行日誌 記錄?什麼情況下需要對異常進行封裝?什麼情況下需要對異常進行替換?對於 捕獲的異常,在什麼情況下需要將其再次拋出?什麼情況下則不需要?
合理的異常處理應該是情境驅動的,在不同的情境下,採用的異常處理策略往 往是不同的。異常處理的策略應該是可配置的,因為應用程式出現怎樣的異常往 往是不可預測的,現有異常策略的不足往往需要在真正出現某種異常的時候才會 體現出來,所以我們需要一種動態可配置的異常處理策略維護方式。目前有一些 開源的異常處理架構提供了這種可配置的、情境驅動的異常處理方式,EntLib的 Exception Handling Application Block(以下簡稱EHAB)就是一個不錯的選擇 。[原始碼從這裡下載]
一、通過指定Handle-Error-Action響應請求
在正式介紹如何通過擴充實現與EntLib以實現自動化異常處理之前,我們不妨 先來體驗一下異常處理具有怎樣的“自動化”特性。以使用者登入情境為例,我們 在通過Visual Studio的ASP.NET MVC項目模板建立的Web應用中定義了如下一個簡 單的資料類型LoginInfo封裝使用者登入需要輸入的使用者名稱和密碼。
1: public class LoginInfo
2: {
3: [DisplayName("使用者名稱")]
4: [Required(ErrorMessage="請輸入{0}")]
5: public string UserName { get; set; }
6:
7: [DisplayName("密碼")]
8: [Required(ErrorMessage = "請輸入{0}")]
9: [DataType(DataType.Password)]
10: public string Password { get; set; }
11: }
然後我們定義了如下一個HomeController。基於HTTP-GET的Action方法Index 將會呈現一個使用者登入View,該View使用建立的LoginInfo對象作為其Model。真 正的使用者驗證邏輯定義在另一個應用了HttpPostAttrubute特性的Index方法中: 如果使用者名稱不為Foo,拋出InvalidUserNameException異常;如果密碼不是 “password”,則拋出InvalidPasswordException異常。 InvalidUserNameException和InvalidPasswordException是我們自訂的兩種異 常類型。
1: [ExceptionPolicy("defaultPolicy")]
2: public class HomeController : ExtendedController
3: {
4: public ActionResult Index()
5: {
6: return View(new LoginInfo());
7: }
8:
9: [HttpPost]
10: [HandleErrorAction("OnIndexError")]
11: public ActionResult Index(LoginInfo loginInfo)
12: {
13: if (string.Compare(loginInfo.UserName, "foo", true) != 0)
14: {
15: throw new InvalidUserNameException();
16: }
17:
18: if (loginInfo.Password != "password")
19: {
20: throw new InvalidPasswordException();
21: }
22: return View(loginInfo);
23: }
24:
25: [HttpPost]
26: public ActionResult OnIndexError(LoginInfo loginInfo)
27: {
28: return View(loginInfo);
29: }
30: }