個人覺得異常處理對於程序員來說是最為熟悉的同時也是最難掌握的。說它熟 悉,因為僅僅就是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: }