.NET/ASP.NET MVC Controller 控制器(深刻解析控制器運行原理)

閱讀目錄:html

  • 1.開篇介紹
  • 2.ASP.NETMVC Controller 控制器的入口(Controller的執行流程)
  • 3.ASP.NETMVC Controller 控制器的入口(Controller的繼承體系)
  • 4.ASP.NETMVC IController Factory 控制器工廠(Controller的建立)

1】開篇介紹

通過前一篇文章.NET/ASP.NET Routing路由(深刻解析路由系統架構原理) 的講解,咱們對ASP.NETRouting路由系統的整個運行機制有了一個基本的瞭解;當咱們能清楚的知道Url是如何被解析成RouteData對象時,下面就是這些路由數據是如何被後面的應用框架所使用的,而通往應用框架的入口是MvcRouteHandler對象;編程

這篇文章將繼續講解經過路由後的ASP.NETMVC Controller控制器是如何被加載、激活而且執行的;跟控制器相關的一套對象模型是被MvcHandler對象做爲源頭調用起來的,也就是說,當咱們穿過UrlRoutingModule對象後,而且成功的獲取到應用框架配置的路由數據後,下面將進入IHttpHandler接口,而這個接口真是咱們初始化RouteData對象時設定的應用框架入口,ASP.NETMVC所使用的是MvcHandler對象;緩存

MvcRouteHandler對象是UrlRoutingModuleMvcHandler對象的鏈接器,只有MvcRouteHandler對象能成功執行後,方能進入到MvcHandler對象中,後續的一切運轉才能順利執行;服務器

2】ASP.NETMVC Controller 控制器的入口(Controller的執行流程)

在系統剛啓動的時候,也就是在Global.asax.cs文件裏面咱們配置了Http客戶端請求服務器的Url模板;在路由解析模塊(UrlRoutingModule)裏面,它將經過字符串級別的操做,解析出咱們Url模板中的{Controller}/{Action}等的佔位符變量;因此這個時候Controller的概念對咱們來講還只是一個字符串而已,而到了目前的這個Controller控制器解析的位置其實已經和路由基本不要緊了,由於咱們穿過了路由模塊到達了Controller解析的環節;Controller解析已經屬於ASP.NETMVC應用框架的範圍,咱們能夠簡單的將路由解析(UrlRoutingModule)的過程視爲將請求的Url(含有數據的Url)與咱們配置的Url模板進行模式匹配的過程,得出匹配後的Url數據(RouteData),而後將Url數據而且連同當前請求上下文一塊兒封裝成RequestContext對象(RouteData、HttpContextBase)傳入到Controller解析的環節,也就是MvcHandler中,做爲MvcHandler構造函數的參數;架構

當MvcHandler接管控制權以後它須要準備好對Controller的解析和執行,可是Controller併發一個簡單的對象,它有一個複雜的繼承體系和使用方式,緣由在於它須要協調多方面的工做因此變的有很複雜;併發

根據MVC的架構模式理論便知道Controller是協調Model與View的中間紐帶,它既要管理好Model的執行,也要管理好View的呈現;而本來MVC的架構模式提出的背景是在WinFrom的狀況下,也就是傳統C/S結構的系統;WinFrom結構的系統有一個好處就是它的執行很方便,從View的展示收集數據到Controller的調度執行Model會容易完成,可是ASP.NETMVC是創建在ASP.NET WEB背景之下的MVC模式框架,因此這個時候對Controller的激活會變的至關麻煩,由於在傳輸過程當中Controller已是字符串形式,若是是在C/S結構中那麼Controller對於每次處理同樣的View不會每次都進行激活;既然每次都須要激活就須要進行緩存策略,緩存策略只是Controller中的一個關鍵點,須要明白的是Controller的確須要作不少事情;框架

圖1:ide

根據上圖的執行順序,能看出Controller控制器扮演着一個很重要的角色,全部的執行、返回值、視圖呈現均須要經過它來管理調度;固然本章的重點是搞清楚此圖中的第一環節,Controller是如何被加載激活的,這裏面將涉及到衆多的輔助對象模型,好比:ControllerFactory控制器工廠,而控制器工廠又將藉助ControllerTypeCache來緩存Controller對象,而ConrollerTypeCache又將藉助TypeCacheSerializer來對Controller緩存文件的序列化;函數

3.ASP.NETMVC Controller 控制器的入口(Controller的繼承體系)

Controller控制器既然扮演着重要的角色,那麼它就不會是一個簡單的對象結構,它有着一個複雜的繼承體系和對象模型支撐它來完成這些艱鉅的任務;Controller要想可以運行起來,就須要搞清楚它有哪些執行入口,而須要知道它有哪些執行入口咱們就須要搞清楚它的繼承體系;入口的最高層抽象在哪一層,這樣咱們才能觸類旁通的擴展Controller的衆多重要的功能;ui

首先咱們瞭解到Controller的頂層抽象是IController接口,而後接着是ControllerBase抽象類實現了這個接口,而做爲頂層抽象的實現ControllerBase完成了從IController接口繼承下來的方法;

1 public interface IController {
2     void Execute(RequestContext requestContext);
3 } 

經過該代碼段能夠看出,Controller的執行須要一個RequestContext對象,而這個對象真是UrlRoutingModule環節所完成的結果,RequestContext對象內部封裝了在Request階段所得到的請求數據,裏面包括了跟Http相關的請求上下文(HttpContextBase),最重要的是路由數據對象(RouteData);而控制器的執行必須須要RouteData中的有關Controller數據對象,也就是從請求Url中經過模式匹配出來的{Controller}部分的字符串;

ControllerBase定義了Controller使用到的部分公共屬性,好比:用來保存臨時數據的TempData,用來返回到View中的Model數據對象ViewBag、ViewData;而且初始化了ControllerContext對象,用來做爲後續Controller使用的數據容器和操做上下文;

1 protected virtual void Initialize(RequestContext requestContext) {
2     ControllerContext = new ControllerContext(requestContext, this);
3 } 

在ControllerBase中將對IController.Execute(RequestContext requestContext)方法調用轉到了protected abstract void ExecuteCore()方法中;這是一個典型的模板方法模式,下面的繼承類Controller,只須要接着protected abstract void ExecuteCore()方法就能和ControllerBase銜接上;

public abstract class Controller : ControllerBase

Controller類繼承自ControllerBase,而Controller的任務只須要完成ExecuteCore()方法;

 1 protected override void ExecuteCore() { 
 2 
 3            PossiblyLoadTempData();
 4            try {
 5               string actionName = RouteData.GetRequiredString("action");
 6                if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {
 7                    HandleUnknownAction(actionName);
 8                }
 9            }
10            finally {
11                PossiblySaveTempData();
12            }
13        } 

Controller.ExecuteCore()的代碼將從RouteData中獲取執行action的名稱,而後經過一個ActionInvoke的組件進行Action的調用,當Action被執行的時候將進入到咱們繼承的Controller,如:HomeController:Controller中,在咱們自定的Controller中的方法都將被視爲Action的匹配目標之一;

圖2:

根據上圖的指示,ControllerBase首先是實現IController接口,完成了對Execute(RequestContext requestContext)方法的實現,而後Controller繼承ControllerBase類,重寫了模板方法ExecuteCore()方法,而後咱們自定義的HomeController實際上是Action的容器,當Controller的ExecuteCore()方法執行時將經過ActionInvoke類進行對HomeController中的方法調用;

4.ASP.NETMVC IController Factory 控制器工廠(Controller的建立)

當清楚了Controller的繼承體系以後,下面回到MvcHandler調用的環節;MvcHandler繼承自IHttpHandler接口 ,表示它將是ASP.NET真正執行請求處理的地方;在MvcHandler處理請求的方法中ProcessRequest(HttpContextBase httpContext),將經過IControllerFactory接口建立IController接口;

IControllerFactory接口是控制器工廠接口,專門用來實現建立IController對象工廠類,在ASP.NETMVC內部有一個實現了IControllerFactory接口的默認工廠類DefaultControllerFactory,ASP.NETMVC內部是用這個類來建立IController對象的;

1 factory = ControllerBuilder.GetControllerFactory();

獲取IDefaultControllerFactory接口須要經過ControllerBuilder對象,ControllerBuilder類是專門用來管理IControllerFactory對象的,同時ControllerBuilder也是應用編程接口,讓自定義IControllerFactory對象成爲可能;

建立IController須要咱們傳入RequestContext對象和ControllerName控制器名稱;

1 // Get the controller type
2 string controllerName = RequestContext.RouteData.GetRequiredString("controller"); 
3 factory = ControllerBuilder.GetControllerFactory();
4 controller = factory.CreateController(RequestContext, controllerName);

從RequestContext.RouteData中獲取到當前請求的conroller名稱,而後用來做爲factory.CreateController的參數;

圖3:

MvcHandler經過ControllerBuilder對象的靜態屬性Current獲取到ControllerBuilder對象實例,顯然ControllerBuilder是一個單例模式的對象;而後經過ControllerBuilder對象獲取到DefaultControllerFactory默認IControllerFactory工廠對象,接着利用DefaultControllerFactory建立出IController對象;

 

相關文章
相關標籤/搜索