如果我想給所有Action注入一段html到頁(yè)面底部,我必須去修改Controller嗎?
如果我想動(dòng)態(tài)控制某個(gè)Action允許由哪些角色訪問(wèn),我通過(guò)修改Controller能實(shí)現(xiàn)嗎?
如果我想這時(shí)候控制的由哪些角色來(lái)訪問(wèn),需求改變時(shí)我想要控制由哪些用戶來(lái)訪問(wèn)呢?我還得去修改Controller嗎?或者增加或修改Filter嗎?
所以需求就出現(xiàn)了:能不能讓我集中管理這些Filter,并且控制的更靈活呢?能讓所有Controller和Action簽名上都干干凈凈的那就最好了。
那就把Filter放在一處集中管理,在Action或ActionResult等執(zhí)行Filter之前保證將需要的Filter準(zhǔn)備好就行了。
在解決問(wèn)題之前,先簡(jiǎn)單回顧一下Action執(zhí)行前后發(fā)生的事。
我們知道,在ASP.NET MVC中,每一次請(qǐng)求通常都定位到一個(gè)具體的Controller的Action中。
在默認(rèn)情況下,由Action執(zhí)行器ControllerActionInvoker類去控制Action的執(zhí)行(或不執(zhí)行),實(shí)際做事的是InvokeAction方法。
InvokeAction方法首先去查找Action(由FindAction方法),如果Action被找到了,會(huì)去檢索該Action擁有的Filter以及該Action所屬Controller的Filter(由GetFilters方法),將找到的所有Filter放入一個(gè)FilterInfo變量中,F(xiàn)ilterInfo中保存的Filter不完全是Action是自己的。然后先執(zhí)行找到的所有IAuthorizationFilter(由InvokeAuthorizationFilters方法)。當(dāng)然,在InvokeAuthorizationFilters方法中,只要有IAuthorizationFilter的ActionResult不為null就會(huì)返回不會(huì)執(zhí)行其他的了。 InvokeAction方法檢測(cè)執(zhí)行結(jié)果,如果ActionResult的確不為空,則執(zhí)行該Result,其他Filter就不管啦。 接著獲取要傳給Action的參數(shù)集(交給GetParameterValue方法),就執(zhí)行InvokeActionMethodWithFilters方法,方法名已經(jīng)足夠說(shuō)明它是干什么的了。如果一切正常,根據(jù)InvokeActionMethodWithFilters方法返回的結(jié)果去接著就執(zhí)行InvokeActionResultWithFilters方法。在執(zhí)行InvokeAuthorizationFilters一直到執(zhí)行InvokeActionResultWithFilters的這一整個(gè)過(guò)程中如果發(fā)生異常,則根據(jù)捕獲的異常執(zhí)行InvokeExceptionFilters進(jìn)行異常處理。
這里需要注意一點(diǎn):InvokeAction、GetFilters、InvokeAuthorizationFilters、GetParameterValue、InvokeActionMethodWithFilters、InvokeActionResultWithFilters、InvokeExceptionFilters等全是虛方法,除非有足夠的原因去繼承IActionInvoker重寫一個(gè)Action執(zhí)行器,否則重寫某些方法足夠擴(kuò)展。
甚至ControllerActionInvoker類本身,在ASP.NET MVC基礎(chǔ)架構(gòu)中也是可以替換的,怎么替換呢?繼承Controller類時(shí)重寫CreateActionInvoker方法就可以。
另外還可以在構(gòu)造Controller對(duì)象給它的ActionInvoker屬性賦值,這又怎么賦值?重寫DefaultControllerFactory創(chuàng)建Controller實(shí)例的GetControllerInstance方法。 然后在Applicaion_Start中設(shè)置新的ControllerFactor:
ControllerBuilder.Current.SetControllerFactory(new YourControllerFactory());
回到主題。 首先我們將Filter和Action的對(duì)應(yīng)關(guān)系(Filter和Controller的對(duì)應(yīng)關(guān)系在本文中暫不討論)存于一個(gè)集合中并緩存起來(lái)。
從找到Action到執(zhí)行InvokeAuthorizationFilters之前,必須將IAuthorizationFilter準(zhǔn)備好;從找到Action到執(zhí)行InvokeActionMethodWithFilters之前,必須將Action需要的IActionFilter準(zhǔn)備好;從找到Action到執(zhí)行InvokeActionResultWithFilters之前,必須將ActionResult需要的IResultFilter準(zhǔn)備好。異常發(fā)生InvokeExceptionFilters執(zhí)行之前,必須將IExceptionFilter準(zhǔn)備好。 基于以上幾點(diǎn),我們好像只能在FindAction方法和GetFilters方法之間選擇一個(gè)。當(dāng)然也就是只有GetFilters了。
在Filter方法中,我們根據(jù)當(dāng)前Action的特征(如方法名,或包括請(qǐng)求方式Get或Post)與Filter和Action對(duì)應(yīng)表。將匹配的Filter加進(jìn)FilterInfo變量中。