摘要
本文將對“MVC公告發布系統”的發布公告功能添加日志功能和異常處理功能,借此來討論ASP.NET MVC中攔截器的使用方法。
一個小難題
我們繼續完善“MVC公告發布系統”,這次,我們的需求是對公告發布功能添加日志記錄能力,即在發布公告前,記錄一次,在 公告發布成功後,再記錄一次。然後還要使得其具備異常處理,即當業務組件出現問題時,跳轉到相應的錯誤頁面並顯示相應提示。
有 人可能笑了,這有什麼難的,在DoRelease這個Action的開始和結束處各加入相應日志功能不久結了。異常處理更不在話下,直接try...catch 搞定。
沒錯,以上方法確實行得通,但是存在以下兩點問題:
1.代碼重復問題。很多日志處理代碼和異常處理代碼是很相似的, 這樣就導致了各個Action中存在大量重復代碼。
2.職責被破壞。不要忘了,我們的Controller僅僅是控制器,它應該只負責表示邏輯, 而不應該被一大堆日志處理代碼和try...catch塊包圍。我們要的Action,應該是干淨的、工整的、僅包含表示邏輯的Action。
以上兩 點,造成了我們系統中的壞味代碼。那麼,怎麼解決這個問題呢?
從廚師到AOP
先來想象一個場景:飯店裡的高級廚師怎麼工作 ?我們知道,他不用洗菜切菜、不用端著盤子送菜、如果發現手裡牛肉變質了他更不用拿著牛肉去找肉店老板理論,他的工作很單一:炒菜。
當原料送來後,有專門的順菜切菜工進行洗菜、切菜,然後把處理好的菜送給廚師,廚師只管下鍋炒,炒完了送菜自然也不必關心,因 為有專門的服務員負責這事。如果發現牛肉變質了,它只管說一聲,自然有相應的人處理這事。
這個場景就是典型的AOP(面向切面編 程)。廚師可以看成是業務組件,它有個方法就是“炒菜”,但是炒菜前要切菜,炒完了要有人送菜,可這不是廚師該關心的事啊 !於是我們的切菜工和服務員就相當於攔截器,其中切菜工在炒菜前攔截,進行切菜,服務員在炒菜後攔截,負責送菜。當然,我們還有個異 常攔截器:處理問題的人,就是那個當廚師發現肉變質了喊一聲,就來處理的人。
基於這個場景,我們看看這樣有什麼好處。首先是廚 師職責單一了,他可以專注於自己的工作:炒菜,而不必理會不該自己關心的問題。而且“攔截器們”可以復用的,例如一個摳門 的老板完全可以找3個廚師但是只招一名服務員,反正一名服務員就可以給三名廚師端菜,這樣,攔截器的復用使得代碼重復不見了!
回來
好的,現在回到我們的“MVC公告發布系統”。相信看了上面的場景,你的靈感一定來了:對啊,Action不就是廚師嗎 ,如果我們可以將日志功能做成攔截器,在DoRelease執行前先攔截一次完成記錄日志功能,DoRelease執行後再攔截一次記錄一次日志。最好 還有個攔截器,在Action發生異常的時候可以攔截處理(就像上文處理變質牛肉的人),不就搞定了嗎。
可是要怎麼實現攔截Action呢 ?真是幸運之極,ASP.NET MVC框架中內置了這種機制!哈哈,我們趕快來做吧!