您好,登錄后才能下訂單哦!
閱讀目錄:
1.開篇介紹
2.ASP.NETMVC Controller 控制器的入口(Controller的執(zhí)行流程)
3.ASP.NETMVC Controller 控制器的入口(Controller的繼承體系)
4.ASP.NETMVC IController Factory 控制器工廠(Controller的創(chuàng)建)
經(jīng)過前一篇文章.NET/ASP.NET Routing路由(深入解析路由系統(tǒng)架構(gòu)原理) 的講解,我們對ASP.NETRouting路由系統(tǒng)的整個運行機制有了一個基本的了解;當(dāng)我們能清楚的知道Url是如何被解析成RouteData對象時,下面就是這些路由數(shù)據(jù)是如何被后面的應(yīng)用框架所使用的,而通往應(yīng)用框架的入口是MvcRouteHandler對象;
這篇文章將繼續(xù)講解通過路由后的ASP.NETMVC Controller控制器是如何被加載、激活并且執(zhí)行的;跟控制器相關(guān)的一套對象模型是被MvcHandler對象作為源頭調(diào)用起來的,也就是說,當(dāng)我們穿過UrlRoutingModule對象后,并且成功的獲取到應(yīng)用框架配置的路由數(shù)據(jù)后,下面將進入IHttpHandler接口,而這個接口真是我們初始化RouteData對象時設(shè)定的應(yīng)用框架入口,ASP.NETMVC所使用的是MvcHandler對象;
MvcRouteHandler對象是UrlRoutingModule和MvcHandler對象的連接器,只有MvcRouteHandler對象能成功執(zhí)行后,方能進入到MvcHandler對象中,后續(xù)的一切運轉(zhuǎn)才能順利執(zhí)行;
在系統(tǒng)剛啟動的時候,也就是在Global.asax.cs文件里面我們配置了Http客戶端請求服務(wù)器的Url模板;在路由解析模塊(UrlRoutingModule)里面,它將通過字符串級別的操作,解析出我們Url模板中的{Controller}/{Action}等的占位符變量;所以這個時候Controller的概念對我們來說還只是一個字符串而已,而到了目前的這個Controller控制器解析的位置其實已經(jīng)和路由基本沒關(guān)系了,因為我們穿過了路由模塊到達了Controller解析的環(huán)節(jié);Controller解析已經(jīng)屬于ASP.NETMVC應(yīng)用框架的范圍,我們可以簡單的將路由解析(UrlRoutingModule)的過程視為將請求的Url(含有數(shù)據(jù)的Url)與我們配置的Url模板進行模式匹配的過程,得出匹配后的Url數(shù)據(jù)(RouteData),然后將Url數(shù)據(jù)并且連同當(dāng)前請求上下文一起封裝成RequestContext對象(RouteData、HttpContextBase)傳入到Controller解析的環(huán)節(jié),也就是MvcHandler中,作為MvcHandler構(gòu)造函數(shù)的參數(shù);
當(dāng)MvcHandler接管控制權(quán)之后它需要準備好對Controller的解析和執(zhí)行,但是Controller并發(fā)一個簡單的對象,它有一個復(fù)雜的繼承體系和使用方式,原因在于它需要協(xié)調(diào)多方面的工作所以變的有很復(fù)雜;
根據(jù)MVC的架構(gòu)模式理論便知道Controller是協(xié)調(diào)Model與View的中間紐帶,它既要管理好Model的執(zhí)行,也要管理好View的呈現(xiàn);而原本MVC的架構(gòu)模式提出的背景是在WinFrom的情況下,也就是傳統(tǒng)C/S結(jié)構(gòu)的系統(tǒng);WinFrom結(jié)構(gòu)的系統(tǒng)有一個好處就是它的執(zhí)行很方便,從View的展現(xiàn)收集數(shù)據(jù)到Controller的調(diào)度執(zhí)行Model會容易完成,但是ASP.NETMVC是建立在ASP.NET WEB背景之下的MVC模式框架,所以這個時候?qū)ontroller的激活會變的相當(dāng)麻煩,因為在傳輸過程中Controller已經(jīng)是字符串形式,如果是在C/S結(jié)構(gòu)中那么Controller對于每次處理一樣的View不會每次都進行激活;既然每次都需要激活就需要進行緩存策略,緩存策略只是Controller中的一個關(guān)鍵點,需要明白的是Controller的確需要做很多事情;
圖1:
根據(jù)上圖的執(zhí)行順序,能看出Controller控制器扮演著一個很重要的角色,所有的執(zhí)行、返回值、視圖呈現(xiàn)均需要通過它來管理調(diào)度;當(dāng)然本章的重點是搞清楚此圖中的第一環(huán)節(jié),Controller是如何被加載激活的,這里面將涉及到眾多的輔助對象模型,比如:ControllerFactory控制器工廠,而控制器工廠又將借助ControllerTypeCache來緩存Controller對象,而ConrollerTypeCache又將借助TypeCacheSerializer來對Controller緩存文件的序列化;
Controller控制器既然扮演著重要的角色,那么它就不會是一個簡單的對象結(jié)構(gòu),它有著一個復(fù)雜的繼承體系和對象模型支撐它來完成這些艱巨的任務(wù);Controller要想能夠運行起來,就需要搞清楚它有哪些執(zhí)行入口,而需要知道它有哪些執(zhí)行入口我們就需要搞清楚它的繼承體系;入口的最高層抽象在哪一層,這樣我們才能舉一反三的擴展Controller的眾多重要的功能;
首先我們了解到Controller的頂層抽象是IController接口,然后接著是ControllerBase抽象類實現(xiàn)了這個接口,而作為頂層抽象的實現(xiàn)ControllerBase完成了從IController接口繼承下來的方法;
public interface IController { void Execute(RequestContext requestContext); }
通過該代碼段可以看出,Controller的執(zhí)行需要一個RequestContext對象,而這個對象真是UrlRoutingModule環(huán)節(jié)所完成的結(jié)果,RequestContext對象內(nèi)部封裝了在Request階段所獲得的請求數(shù)據(jù),里面包括了跟Http相關(guān)的請求上下文(HttpContextBase),最重要的是路由數(shù)據(jù)對象(RouteData);而控制器的執(zhí)行必須需要RouteData中的有關(guān)Controller數(shù)據(jù)對象,也就是從請求Url中通過模式匹配出來的{Controller}部分的字符串;
ControllerBase定義了Controller使用到的部分公共屬性,比如:用來保存臨時數(shù)據(jù)的TempData,用來返回到View中的Model數(shù)據(jù)對象ViewBag、ViewData;并且初始化了ControllerContext對象,用來作為后續(xù)Controller使用的數(shù)據(jù)容器和操作上下文;
protected virtual void Initialize(RequestContext requestContext) { ControllerContext = new ControllerContext(requestContext, this); }
在ControllerBase中將對IController.Execute(RequestContext requestContext)方法調(diào)用轉(zhuǎn)到了protected abstract void ExecuteCore()方法中;這是一個典型的模板方法模式,下面的繼承類Controller,只需要接著protected abstract void ExecuteCore()方法就能和ControllerBase銜接上;
public abstract class Controller : ControllerBase
Controller類繼承自ControllerBase,而Controller的任務(wù)只需要完成ExecuteCore()方法;
protected override void ExecuteCore() { PossiblyLoadTempData(); try { string actionName = RouteData.GetRequiredString("action"); if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) { HandleUnknownAction(actionName); } } finally { PossiblySaveTempData(); } }
Controller.ExecuteCore()的代碼將從RouteData中獲取執(zhí)行action的名稱,然后通過一個ActionInvoke的組件進行Action的調(diào)用,當(dāng)Action被執(zhí)行的時候?qū)⑦M入到我們繼承的Controller,如:HomeController:Controller中,在我們自定的Controller中的方法都將被視為Action的匹配目標之一;
圖2:
根據(jù)上圖的指示,ControllerBase首先是實現(xiàn)IController接口,完成了對Execute(RequestContext requestContext)方法的實現(xiàn),然后Controller繼承ControllerBase類,重寫了模板方法ExecuteCore()方法,然后我們自定義的HomeController其實是Action的容器,當(dāng)Controller的ExecuteCore()方法執(zhí)行時將通過ActionInvoke類進行對HomeController中的方法調(diào)用;
當(dāng)清楚了Controller的繼承體系之后,下面回到MvcHandler調(diào)用的環(huán)節(jié);MvcHandler繼承自IHttpHandler接口 ,表示它將是ASP.NET真正執(zhí)行請求處理的地方;在MvcHandler處理請求的方法中Proce***equest(HttpContextBase httpContext),將通過IControllerFactory接口創(chuàng)建IController接口;
IControllerFactory接口是控制器工廠接口,專門用來實現(xiàn)創(chuàng)建IController對象工廠類,在ASP.NETMVC內(nèi)部有一個實現(xiàn)了IControllerFactory接口的默認工廠類DefaultControllerFactory,ASP.NETMVC內(nèi)部是用這個類來創(chuàng)建IController對象的;
factory = ControllerBuilder.GetControllerFactory();
獲取IDefaultControllerFactory接口需要通過ControllerBuilder對象,ControllerBuilder類是專門用來管理IControllerFactory對象的,同時ControllerBuilder也是應(yīng)用編程接口,讓自定義IControllerFactory對象成為可能;
創(chuàng)建IController需要我們傳入RequestContext對象和ControllerName控制器名稱;
// Get the controller type string controllerName = RequestContext.RouteData.GetRequiredString("controller"); factory = ControllerBuilder.GetControllerFactory(); controller = factory.CreateController(RequestContext, controllerName);
從RequestContext.RouteData中獲取到當(dāng)前請求的conroller名稱,然后用來作為factory.CreateController的參數(shù);
圖3:
MvcHandler通過ControllerBuilder對象的靜態(tài)屬性Current獲取到ControllerBuilder對象實例,顯然ControllerBuilder是一個單例模式的對象;然后通過ControllerBuilder對象獲取到DefaultControllerFactory默認IControllerFactory工廠對象,接著利用DefaultControllerFactory創(chuàng)建出IController對象;
作者:王清培
出處:http://wangqingpei557.blog.51cto.com/
本文版權(quán)歸作者和51CTO共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。