關於ASP.NET MVC對請求的處理方式(同步或者異步)涉及到的五個組件,在《上篇》中我們談了三個(MvcHandler、Controller和ActionInvoker),現在我們來談余下的兩個,即ControllerDescriptor和ActionDescriptor,這五個組件的執行並非孤立的,而是具有議定的關系。相信讀者認真閱讀了這兩篇文章後,會對整個請求的處理方式有一個深刻的理解。
四、ControllerDescriptor的同步與異步
如果采用ControllerActionInvoker,Action總是以同步的方式來直接,但是當AsyncControllerActionInvoker作為Controller的ActionInvoker時,並不意味著總是以異步的方式來執行所有的Action。至於這兩種類型的ActionInvoker具體采用對Action的怎樣的執行方式,又涉及到兩個描述對象,即用於描述Controller和Action的ControllerDescriptor和ActionDescriptor。
通過前面“Model的綁定”中對這兩個對象進行過相應的介紹,我們知道在ASP.NET MVC應用編程接口中具有兩個具體的ControllerDescriptor,即ReflectedControllerDescriptor和ReflectedAsyncControllerDescriptor,它們分別代表同步和異步版本的ControllerDescriptor。
1: public class ReflectedControllerDescriptor : ControllerDescriptor
2: {
3: //省略成員
4: }
5:
6: public class ReflectedAsyncControllerDescriptor : ControllerDescriptor
7: {
8: //省略成員
9: }
ReflectedControllerDescriptor和ReflectedAsyncControllerDescriptor並非對分別實現了IController和IAyncController接口的Controller的描述,而是對直接繼承自抽象類Controller和AsyncController的Controller的描述。它們之間的區別在於創建者的不同,在默認情況下ReflectedControllerDescriptor和ReflectedAsyncControllerDescriptor分別是通過ControllerActionInvoker和AsyncControllerActionInvoker來創建的。ActionInvoker和ControllerDescriptor之間的關系可以通過如下圖所示的UML來表示。
ActionInvoker與ControllerDescriptor之間的關系可以通過一個簡單的實例來驗證。在通過Visual Studio的ASP.NET MVC項目模板創建的空Web應用中,我們自定義了如下兩個分別繼承自ControllerActionInvoker和AsyncControllerActionInvoker的ActionInvoker類型。在這兩個自定義ActionInvoker中,定義了公有的GetControllerDescriptor方法覆蓋了基類的同名方法(受保護的虛方法),並直接直接調用基類的同名方法根據提供的Controller上下文的到相應的ControllerDescriptor對象。
1: public class FooActionInvoker : ControllerActionInvoker
2: {
3: public new ControllerDescriptor GetControllerDescriptor(ControllerContext controllerContext)
4: {
5: return base.GetControllerDescriptor(controllerContext);
6: }
7: }
8:
9: public class BarActionInvoker : AsyncControllerActionInvoker
10: {
11: public new ControllerDescriptor GetControllerDescriptor(ControllerContext controllerContext)
12: {
13: return base.GetControllerDescriptor(controllerContext);
14: }
15: }
然後我們定義了兩個Controller類型,它們均是抽象類型Controller的直接繼承者。如下面的代碼片斷所示,這兩Controller類(FooController和BarController)都重寫了虛方法CreateActionInvoker,而返回的ActionInvoker類型分別是上面我們定義的FooActionInvoker和BarActionInvoker。在默認的Action方法Index中,我們利用當前的ActionInvoker得到用於描述本Controller的ControllerDescriptor對象,並將其類型呈現出來。
1: public class FooController : Controller
2: {
3: protected override IActionInvoker CreateActionInvoker()
4: {
5: return new FooActionInvoker();
6: }
7:
8: public void Index()
9: {
10: ControllerDescriptor controllerDescriptor = ((FooActionInvoker)this.ActionInvoker).GetControllerDescriptor(ControllerContext);
11: Response.Write(controllerDescriptor.GetType().FullName);
12: }
13: }
14:
15: public class BarController : Controller
16: {
17: protected override IActionInvoker CreateActionInvoker()
18: {
19: return new BarActionInvoker();
20: }
21:
22: public void Index()
23: {
24: ControllerDescriptor controllerDescriptor = ((BarActionInvoker)this.ActionInvoker).GetControllerDescriptor(ControllerContext);
25: Response.Write(controllerDescriptor.GetType().FullName);
26: }
27: }