系列目錄
回顧
系列的前4節深入剖析了ASP.NET URL路由機制,以及MVC在此基礎上是如何?Areas機制的,同時涉及到inbound和outbound很多細節部分。第2節中提到MvcRouteHandler是MVC架構的入口,這節開始,從MvcRouteHandler往下說開去。
Controller的建立過程:Builder和Factory
MvcRouteHandler的實現僅僅是通過GetHttpHandler方法返回一個MvcHandler執行個體,MvcHandler從RouteData中獲得controller名字負責建立一個ControllerBuilder的執行個體,並通過ControllerBuilder的GetControllerFactory返回一個IControllerFactory的執行個體,這個執行個體就是DefaultControllerFactory,它的 CreateController方法負責建立需要的Controller執行個體。下面這段代碼來自MvcHandler:
// Get the controller typestring controllerName = RequestContext.RouteData.GetRequiredString("controller");// Instantiate the controller and call Executefactory = ControllerBuilder.GetControllerFactory();controller = factory.CreateController(RequestContext, controllerName);
DefaultControllerFactory建立Controller分兩步:
Type controllerType = GetControllerType(requestContext, controllerName);IController controller = GetControllerInstance(requestContext, controllerType);
GetControllerInstance最終是這樣建立controller的:
return (IController)Activator.CreateInstance(controllerType);
這就使得要使用DI設計模式十分困難。好在我們可以重寫GetControllerInstance,並應用各種DI。受書中的影響,個人使用的是Ninject。
另外,為了加快GetControllerType方法,DefaultControllerFactory內部運用緩衝機制將當前程式和所有引用程式集的類型緩衝成雜湊表。
還可以通過如下方法,提供某些名字空間較高的優先順序來最佳化搜尋。
protected void Application_Start() { RegisterRoutes(RouteTable.Routes); ControllerBuilder.Current.DefaultNamespaces.Add("MyApp.Controllers.*"); ControllerBuilder.Current.DefaultNamespaces.Add("OtherAssembly.MyNamespace.*"); }
上面這種設定名字空間的優先順序仍然低於在設定路由表時為某個路由指定的名字空間,Areas機制就是靠在設定路由表時指定名字空間實現的,詳見深入理解ASP.NET MVC(4)。
也可以在ControllerBuilder層面上替換ControllerFactory:
protected void Application_Start() { RegisterRoutes(RouteTable.Routes); ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory()); }
Controller的調用:Controller只是普通的.NET類
MvcHandler依靠ControllerBuilder和IControllerFactory獲得Controller的執行個體後,調用Controller執行個體的Execute方法,在該方法返回後再調用IControllerFactory的ReleaseController收尾。由此看出Controller的Execute做了所有的事情,看似“功能強大”,其實它只是.NET的普通類, MVC架構賦予其“非凡”的能力:
所有的Controller只要實現一個介面,IController,介面的定義了Execute方法:
namespace System.Web.Mvc { using System.Web.Routing; public interface IController { void Execute(RequestContext requestContext); }}
從介面定義可以看出,當Controller被“調用”的時候,應該負責完成Execute方法,參數RequestContext封裝了HttpContext,所以可以像下面這樣直接實現一個Controller,同樣可以工作:
public class HelloWorldController : IController { public void Execute(RequestContext requestContext) { requestContext.HttpContext.Response.Write("Hello, world!"); } }
然而,需要的邏輯和架構遠比這個複雜的多,因此MVC架構提供了如下類別關係:
IController->ControllerBase->Controller
其中ControllerBase實現Execute,Execute在內部調用ExecuteCore,ExecuteCore作為一個抽象方法,延遲到Controller中實現。ControllerBase只提供了諸如TempData、ViewData等,Controller的ExecuteCore方法真正invoke了action機制,是action的入口。下面的代碼是ExecuteCore的實現:
PossiblyLoadTempData();try { string actionName = RouteData.GetRequiredString("action"); if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) { HandleUnknownAction(actionName); } } finally { PossiblySaveTempData(); }
可以看到RouteData在這裡又提供了action參數,可以想象InvokeAction方法依靠這個action的名字調用action,並實現諸多驗證機制。下節開始討論action邏輯。
勞動果實,轉載請註明出處:http://www.cnblogs.com/P_Chou/archive/2010/11/20/details-asp-net-mvc-05.html