自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

詳解ASP.NET MVC Controller激活系統(tǒng):總體設(shè)計(jì)

開(kāi)發(fā) 后端
本文將給大家談?wù)凙SP.NET MVC Controller激活系統(tǒng)。包括Controller激活系統(tǒng)在ASP.NET MVC中的總體設(shè)計(jì),了解一下組成該子系統(tǒng)的一些基本的組件,以及它們對(duì)應(yīng)的接口或者抽象類是什么。

我們將整個(gè)ASP.NET MVC框架劃分為若干個(gè)子系統(tǒng),那么針對(duì)請(qǐng)求上下文激活目標(biāo)Controller對(duì)象的子系統(tǒng)被我們成為Controller激活系統(tǒng)。在正式討論Controller對(duì)象具體是如何被創(chuàng)建愛(ài)之前,我們先來(lái)看看Controller激活系統(tǒng)在ASP.NET MVC中的總體設(shè)計(jì),了解一下組成該子系統(tǒng)的一些基本的組件,以及它們對(duì)應(yīng)的接口或者抽象類是什么。

目錄

一、Controller
二、 ControllerFactory
三、ControllerBuilder
實(shí)例演示:如何提升命名空間的優(yōu)先級(jí)
針對(duì)Area的路由對(duì)象的命名空間
四、 Controller的激活與URL路由

一、Controller

我們知道作為Controller的類型直接或者間接實(shí)現(xiàn)了IController接口。如下面的代碼片斷所示,IController接口僅僅包含一個(gè)參數(shù)類型為RequestContext的Execute方法。當(dāng)一個(gè)Controller對(duì)象被激活之后,核心的操作就是根據(jù)請(qǐng)求上下文解析出目標(biāo)Action方法,并通過(guò)Model綁定機(jī)制從請(qǐng)求上下文中提取相應(yīng)的數(shù)據(jù)映射為方法的參數(shù)并最終執(zhí)行Action方法。所有的這些操作都是調(diào)用這個(gè)Execute方法來(lái)執(zhí)行的。

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

定義在IController接口中的Execute是以同步的方式執(zhí)行的。為了支持以異步方式對(duì)請(qǐng)求的處理,IController接口的異步版本System.Web.Mvc.IAsyncController被定義出來(lái)。如下面的代碼片斷所示,實(shí)現(xiàn)了IAsyncController接口的異步Controller的執(zhí)行通過(guò)BeginExecute/EndExecute方法組合來(lái)完成。

  1. public interface IAsyncController : IController  
  2.    {  
  3.        IAsyncResult BeginExecute(RequestContext requestContext, AsyncCallback callback, object state);  
  4.       void EndExecute(IAsyncResult asyncResult);  
  5.     } 

抽象類ControllerBase實(shí)現(xiàn)了IController接口,它具有如下幾個(gè)重要的屬性。TemplateData、ViewBag和ViewData用于存儲(chǔ)從Controller向View傳遞的數(shù)據(jù)或者變量。其中TemplateData和ViewData具有基于字典的數(shù)據(jù)結(jié)構(gòu),Key和Value分別表示變量的名稱和值,所不同的前者用于存儲(chǔ)基于當(dāng)前HTTP上下文的變量(在完成當(dāng)前請(qǐng)求后,存儲(chǔ)的數(shù)據(jù)會(huì)被回收)。ViewBag和ViewData具有相同的作用,甚至對(duì)應(yīng)著相同的數(shù)據(jù)存儲(chǔ),它們之間的不同之處在于前者是一個(gè)動(dòng)態(tài)對(duì)象,我們可以為其指定任意屬性。

  1. public abstract class ControllerBase : IController  
  2. {     
  3.     //其他成員  
  4.    public ControllerContext ControllerContext { getset; }  
  5.     public TempDataDictionary TempData { getset; }  
  6.     public object ViewBag { [return: Dynamic] get; }  
  7.    public ViewDataDictionary ViewData { getset; }  

在ASP.NET MVC中我們會(huì)陸續(xù)遇到一系列的上下文(Context)對(duì)象,之前我們已經(jīng)對(duì)表示請(qǐng)求上下文的RequestContext(HttpContext + RouteData)進(jìn)行了詳細(xì)的介紹,現(xiàn)在我們來(lái)介紹另一個(gè)具有如下定義的上下文類型ControllerContext。

  1. public class ControllerContext  
  2.  {  
  3.      //其他成員  
  4.      public ControllerContext();  
  5.      public ControllerContext(RequestContext requestContext, ControllerBase controller);  
  6.     public ControllerContext(HttpContextBase httpContext,   
  7.      RouteData routeData, ControllerBase controller);  
  8.      public virtual ControllerBase Controller { getset; }  
  9.    public RequestContext RequestContext { getset; }  
  10.     public virtual HttpContextBase HttpContext { getset; }  
  11.     public virtual RouteData RouteData { getset; }  

顧名思義,ControllerContext就是基于某個(gè)Controller對(duì)象的上下文。從如下的代碼所示,ControllerContext是實(shí)際上是對(duì)一個(gè)Controller對(duì)象和RequestContext的封裝,這兩個(gè)對(duì)象分別對(duì)應(yīng)著定義在ControllerContext中的同名屬性,并且可以在構(gòu)造函數(shù)中被初始化。而通過(guò)屬性HttpContext和RouteData屬性返回的HttpContextBase和RouteData對(duì)象在默認(rèn)情況下實(shí)際上就是組成RequestContext的核心元素。ControllerContext的這四個(gè)屬性都是可讀可寫(xiě)的,我們對(duì)其進(jìn)行任意地修改。當(dāng)ControllerBase的Execute方法被執(zhí)行的時(shí)候,它會(huì)根據(jù)傳入的ReuqestContext創(chuàng)建ControllerContext對(duì)象,而后續(xù)的操作可以看成是在該上下文中進(jìn)行。

當(dāng)我們?cè)谶M(jìn)行開(kāi)發(fā)的時(shí)候,通過(guò)VS默認(rèn)創(chuàng)建的Controller類型實(shí)際上繼承自抽象類Controller。該類型中定義了很多的輔助方法和屬性以編程變得簡(jiǎn)單。如下面的代碼片斷所示,除了直接繼承ControllerBase之外,Controller類型還顯式實(shí)現(xiàn)了IController和IAsyncController接口,以及代表ASP.NET MVC 四大篩選器(AuthorizationFilter、ActionFilter、ResultFilter和ExceptionFilter)的4個(gè)接口。

  1. public abstract class Controller :   
  2.      ControllerBase,        
  3.      IController,   
  4.     IAsyncController,  
  5.      IActionFilter,   
  6.      IAuthorizationFilter,   
  7.      IExceptionFilter,   
  8.     IResultFilter,    
  9.      IDisposable,   
  10.    ...  
  11. {  
  12.    //省略成員  

二、 ControllerFactory

ASP.NET MVC為Controller的激活定義相應(yīng)的相應(yīng)的工廠,我們將其統(tǒng)稱為ControllerFactory,所有的ControllerFactory實(shí)現(xiàn)了接口IControllerFactory接口。如下面的代碼片斷所示,Controller對(duì)象的激活最終最終通過(guò)IControllerFactory的CreateController方法來(lái)完成,該方法的兩個(gè)參數(shù)分別表示當(dāng)前請(qǐng)求上下文和從路由信息中獲取的Controller的名稱(最初來(lái)源于請(qǐng)求地址)。

  1. public interface IControllerFactory  
  2.  {  
  3.     IController CreateController(RequestContext requestContext, string controllerName);  
  4.     SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);  
  5.     void ReleaseController(IController controller);  
  6.  }  
  7. public enum SessionStateBehavior  
  8.  
  9.      Default,  
  10.    Required,  
  11.    ReadOnly,  
  12.    Disabled  

處理負(fù)責(zé)創(chuàng)建Controller處理請(qǐng)求之前,ControllerFactory還需要在完成請(qǐng)求處理之后實(shí)施對(duì)Controller的釋放回收,后者實(shí)現(xiàn)在ReleaseController方法中。IControllerFactory的另一個(gè)方法GetControllerSessionBehavior方法返回一個(gè)SessionStateBehavior枚舉。熟悉ASP.NET的讀者應(yīng)該對(duì)SessionStateBehavior不會(huì)感到陌生,它用于表示請(qǐng)求處理過(guò)程中會(huì)話狀態(tài)支持的模式,它的四個(gè)枚舉值分別具有如下的含義:

  • Default:使用默認(rèn) ASP.NET 邏輯來(lái)確定請(qǐng)求的會(huì)話狀態(tài)行為。
  • Required:為請(qǐng)求啟用完全的讀寫(xiě)會(huì)話狀態(tài)行為。
  • ReadOnly:為請(qǐng)求啟用只讀會(huì)話狀態(tài)。
  • Disabled:禁用會(huì)話狀態(tài)。

對(duì)于Default選項(xiàng)來(lái)說(shuō),ASP.NET通過(guò)映射的HttpHandler類型是否實(shí)現(xiàn)了相關(guān)接口來(lái)決定具體的會(huì)話狀態(tài)控制行為。在System.Web.SessionState命名空間下定義了IRequiresSessionState和IRequiresSessionState接口,如下面的代碼片斷所示,這兩個(gè)都是不具有任何成員的空接口(我們一般稱之為標(biāo)記接口),而IReadOnlySessionState繼承自IRequiresSessionState。如果HttpHandler實(shí)現(xiàn)了接口IReadOnlySessionState,則意味著采用ReadOnly模式,如果只實(shí)現(xiàn)了IRequiresSessionState則采用Required模式。

   1: public interface IRequiresSessionState
   2: {}
   3: public interface IReadOnlySessionState : IRequiresSessionState
   4: {}

具體采用何種會(huì)話狀態(tài)行為取決于當(dāng)前HTTP上下文(HttpContext.Current)。對(duì)于之前的版本,我們不能對(duì)當(dāng)前HTTP上下文的會(huì)話狀態(tài)行為模式進(jìn)行動(dòng)態(tài)的修改,ASP.NET 4.0為HttpContext定義了如下一個(gè)SetSessionStateBehavior方法是我們可以自由地選擇會(huì)話狀態(tài)行為模式。相同的方法同樣定義在HttpContextBase中,它的子類HttpContextWrapper重寫(xiě)了這個(gè)方法并在內(nèi)部會(huì)調(diào)用封裝的HttpContext的同名方法。

  1. public sealed class HttpContext : IServiceProvider, IPrincipalContainer  
  2.  {  
  3.     //其他成員  
  4.  public void SetSessionStateBehavior(  
  5.      SessionStateBehavior sessionStateBehavior);  
  6.  }  
  7.  public class HttpContextBase: IServiceProvider  
  8.  {  
  9.     //其他成員  
  10.     public void SetSessionStateBehavior(SessionStateBehavior sessionStateBehavior);  

三、ControllerBuilder

用于激活Controller對(duì)象的ControllerFactory最終通過(guò)ControllerBuilder注冊(cè)到ASP.NET MVC應(yīng)用中。如下面的代碼所示,ControllerBuilder定義了一個(gè)靜態(tài)只讀屬性Current返回當(dāng)前ControllerBuilder對(duì)象,這是針對(duì)整個(gè)Web應(yīng)用的全局對(duì)象。兩個(gè)SetControllerFactory方法重載用于注冊(cè)ControllerFactory的類型或者實(shí)例,而GetControllerFactory方法返回一個(gè)具體的ControllerFactory對(duì)象。

  1. public class ControllerBuilder  
  2.  
  3.     public IControllerFactory GetControllerFactory();  
  4.    public void SetControllerFactory(Type controllerFactoryType);  
  5.     public void SetControllerFactory(IControllerFactory controllerFactory);    
  6.     public HashSet<string> DefaultNamespaces { get; }  
  7.    public static ControllerBuilder Current { get; }  

具體來(lái)說(shuō),如果我們是注冊(cè)的ControllerFactory的類型,那么GetControllerFactory在執(zhí)行的時(shí)候會(huì)通過(guò)對(duì)注冊(cè)類型的反射(調(diào)用Activator的靜態(tài)方法CreateInstance)來(lái)創(chuàng)建具體的ControllerFactory(系統(tǒng)不會(huì)對(duì)創(chuàng)建的Controller進(jìn)行緩存);如果注冊(cè)的是一個(gè)具體的ControllerFactory對(duì)象,該對(duì)象直接從GetControllerFactory返回。

被ASP.NET路由系統(tǒng)進(jìn)行攔截處理后會(huì)生成一個(gè)用于封裝路由信息的RouteData對(duì)象,而目標(biāo)Controller的名稱就包含在通過(guò)該RouteData的Values屬性表示的RouteValueDisctionary對(duì)象中,對(duì)應(yīng)的Key為“controller”。而在默認(rèn)的情況下,這個(gè)作為路由數(shù)據(jù)的名稱只能幫助我們解析出Controller的類型名稱,如果我們?cè)诓煌拿臻g下定義了多個(gè)同名的Controller類,會(huì)導(dǎo)致激活系統(tǒng)無(wú)法確定具體的Controller的類型從而拋出異常。

為了解決這個(gè)問(wèn)題,我們必須為定義了同名Controller類型的命名空間設(shè)置不同的優(yōu)先級(jí),具體來(lái)說(shuō)我們有兩種提升命名空間優(yōu)先級(jí)的方式。***種方式就是在調(diào)用RouteCollection的擴(kuò)展方法MapRoute時(shí)指定一個(gè)命名空間的列表。通過(guò)這種方式指定的命名空間列表會(huì)保存在Route對(duì)象的DataTokens屬性表示的RouteValueDictionary字典中,對(duì)應(yīng)的Key為“Namespaces”。

  1. public static class RouteCollectionExtensions  
  2.  {  
  3.      //其他成員        
  4.      public static Route MapRoute(this RouteCollection routes, string name, string url, string[] namespaces);      
  5.      public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, string[] namespaces);      
  6.      public static Route MapRoute(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces);  
  7.  }  

而另一種提升命名空間優(yōu)先級(jí)的方式就是將其添加到當(dāng)前的ControllerBuilder中的默認(rèn)命名空間列表中。從上面的給出的ControllerBuilder的定義可以看出,它具有一個(gè)HashSet<string>類型的只讀屬性DefaultNamespaces就代表了這么一個(gè)默認(rèn)命名空間列表。對(duì)于這兩種不同的命名空間優(yōu)先級(jí)提升方式,前者(通過(guò)路由注冊(cè))指定命名空間具有更高的優(yōu)先級(jí)。

實(shí)例演示:如何提升命名空間的優(yōu)先級(jí)

為了讓讀者對(duì)此如何提升命名空間優(yōu)先級(jí)具有一個(gè)深刻的印象,我們來(lái)進(jìn)行一個(gè)簡(jiǎn)單的實(shí)例演示。我們使用Visual Studio提供的項(xiàng)目模板創(chuàng)建一個(gè)空的ASP.NET MVC應(yīng)用,并且使用如下所示的默認(rèn)路由注冊(cè)代碼。

  1.  public class MvcApplication : System.Web.HttpApplication  
  2.  {  
  3.      public static void RegisterRoutes(RouteCollection routes)  
  4.      {        
  5.          routes.MapRoute(  
  6.              name: "Default",  
  7.              url: "{controller}/{action}/{id}",  
  8.              defaults: new { controller = "Home", action = "Index",   
  9.                  id = UrlParameter.Optional }  
  10.         );  
  11.    }  
  12.     protected void Application_Start()  
  13.     {  
  14.         //其他操作  
  15.         RegisterRoutes(RouteTable.Routes);  
  16.     }  
  17. }  
  18. public class MvcApplication : System.Web.HttpApplication  
  19. {  
  20.     public static void RegisterRoutes(RouteCollection routes)  
  21.     {        
  22.         routes.MapRoute(  
  23.             name: "Default",  
  24.             url: "{controller}/{action}/{id}",  
  25.             defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }  
  26.         );  
  27.     }  
  28.     protected void Application_Start()  
  29.     {  
  30.         //其他操作  
  31.         RegisterRoutes(RouteTable.Routes);  
  32.     }  

然后我們?cè)贑ontrollers目錄下添加一個(gè).cs 文件,并在該文件中定義兩個(gè)同名的Controller類。如下面的代碼片斷所示,這兩個(gè)HomeCotroller類分別定義在命名空間Artech.MvcAppArtech.MvcApp.Controllers之中,而Index操作返回的是一個(gè)將Controller類型全名為內(nèi)容的ContentResult對(duì)象。

  1.  namespace Artech.MvcApp.Controllers  
  2.  {  
  3.      public class HomeController : Controller  
  4.      {  
  5.          public ActionResult Index()  
  6.          {  
  7.              return this.Content(this.GetType().FullName);  
  8.          }  
  9.      }  
  10.  
  11. namespace Artech.MvcApp  
  12. {  
  13.     public class HomeController : Controller  
  14.    {  
  15.         public ActionResult Index()  
  16.        {  
  17.            return this.Content(this.GetType().FullName);  
  18.        }  
  19.    }  

現(xiàn)在我們直接運(yùn)行該Web應(yīng)用。由于具有多個(gè)Controller與注冊(cè)的路由規(guī)則相匹配導(dǎo)致ASP.NET MVC的Controller激活系統(tǒng)無(wú)法確定目標(biāo)哪個(gè)類型的Controller應(yīng)該被選用,所以會(huì)出現(xiàn)如下圖所示的錯(cuò)誤。

image

目前定義了HomeController的兩個(gè)命名空間具有相同的優(yōu)先級(jí),現(xiàn)在我們將其中一個(gè)定義在當(dāng)前ControllerBuilder的默認(rèn)命名空間列表中以提升匹配優(yōu)先級(jí)。如下面的代碼片斷所示,在Global.asax 的Application_Start方法中,我們將命名空間“Artech.MvcApp.Controllers”添加到當(dāng)前ControllerBuilder的DefaultNamespaces屬性所示的命名空間列表中。

   1: public class MvcApplication : System.Web.HttpApplication
   2: {
   3:     protected void Application_Start()
   4:     {
   5:         //其他操作            
   6:         ControllerBuilder.Current.DefaultNamespaces.Add("Artech.MvcApp.Controllers");
   7:     }
   8: }

對(duì)用同時(shí)匹配注冊(cè)的路由規(guī)則的兩個(gè)HomeController,由于“Artech.MvcApp.Controllers”命名空間具有更高的匹配優(yōu)先級(jí),所有定義其中的HomeController會(huì)被選用,這可以通過(guò)如下圖所示的運(yùn)行結(jié)果看出來(lái)。

image

為了檢驗(yàn)在路由注冊(cè)時(shí)指定的命名空間和作為當(dāng)前ControllerBuilder的命名空間哪個(gè)具有更高匹配優(yōu)先級(jí),我們修改定義在Global.asax中的路由注冊(cè)代碼。如下面的代碼片斷所示,我們在調(diào)用RouteTable的靜態(tài)屬性Routes的MapRoute方法進(jìn)行路由注冊(cè)的時(shí)候指定了命名空間(“Artech.MvcApp”)。

  1. public class MvcApplication : System.Web.HttpApplication  
  2. {  
  3.     public static void RegisterRoutes(RouteCollection routes)  
  4.     {        
  5.         routes.MapRoute(  
  6.             name: "Default",  
  7.             url: "{controller}/{action}/{id}",  
  8.             defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },  
  9.             namespaces:new string[]{"Artech.MvcApp"}  
  10.        );  
  11.    }  
  12.     protected void Application_Start()  
  13.   {  
  14.       //其他操作  
  15.       RegisterRoutes(RouteTable.Routes);   
  16.      ControllerBuilder.Current.DefaultNamespaces.Add("Artech.MvcApp.Controllers");  
  17.    }  

再次運(yùn)行我們的程序會(huì)在瀏覽器中得到如圖3-3所示的結(jié)果,從中可以看出定義在命名空間“Artech.MvcApp”中的HomeController被最終選用,可見(jiàn)較之作為當(dāng)前ControllerBuilder的默認(rèn)命名空間,在路由注冊(cè)過(guò)程中執(zhí)行的命名空間具有更高的匹配優(yōu)先級(jí),前者可以視為后者的一種后備。

image

在路由注冊(cè)時(shí)指定的命名空間比當(dāng)前ControllerBuilder的默認(rèn)命名空間具有更高的匹配優(yōu)先級(jí),但是對(duì)于這兩個(gè)集合中的所有命名空間卻具有相同的匹配優(yōu)先級(jí)。換句話說(shuō),用于輔助解析Controller類新的命名空間分為三個(gè)梯隊(duì),簡(jiǎn)稱為路由命名空間、ConrollerBuilder命名空間和Controller類型命名空間,如果前一個(gè)梯隊(duì)不能正確解析出目標(biāo)Controller的類型,則將后一個(gè)梯隊(duì)的命名空間作為后備;反之,如果根據(jù)某個(gè)梯隊(duì)的命名空間進(jìn)行解析得到多個(gè)匹配的Controller類型,會(huì)直接拋出異常。

現(xiàn)在我們對(duì)本例的路由注冊(cè)代碼作了如下的修改,為注冊(cè)的路由對(duì)象指定了兩個(gè)命名空間(分別是兩個(gè)HomeContrller所在的命名空間),運(yùn)行我們的程序依然會(huì)得到如***張圖所示的錯(cuò)誤。

  1.  public class MvcApplication : System.Web.HttpApplication  
  2.  {  
  3.      public static void RegisterRoutes(RouteCollection routes)  
  4.      {        
  5.          routes.MapRoute(  
  6.              name: "Default",  
  7.              url: "{controller}/{action}/{id}",  
  8.              defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },  
  9.              namespaces: new string[] { "Artech.MvcApp""Artech.MvcApp.Controllers" }  
  10.         );  
  11.     }  
  12.     protected void Application_Start()  
  13.   {  
  14.         //其他操作  
  15.      RegisterRoutes(RouteTable.Routes);  
  16.    }  

針對(duì)Area的路由對(duì)象的命名空間

針對(duì)某個(gè)Area的路由映射是通過(guò)相應(yīng)的AreaRegistration進(jìn)行注冊(cè)的,具體來(lái)說(shuō)是在AreaRegistration的RegisterArea方法中調(diào)用AreaRegistrationContext對(duì)象的MapRoute方法進(jìn)行注冊(cè)的。如果在調(diào)用MapRoute方法中指定了表示命名空間的字符串,將自動(dòng)作為注冊(cè)的路由對(duì)象的命名空間,否則會(huì)將表示AreaRegistration所在命名空間的字符串加上“.*”后綴作為路由對(duì)象的命名空間。這里所說(shuō)的“路由對(duì)象的命名空間”指的就是通過(guò)Route對(duì)象的DataTokens屬性表示的RouteValueDictionary對(duì)象中Key為“Namespaces”的字符串?dāng)?shù)組,而該字符串最終會(huì)轉(zhuǎn)移到生成的RouteData的DataTokens中。

除此之外,在調(diào)用AreaRegistrationContext的MapRoute方法時(shí)還會(huì)在注冊(cè)Route對(duì)象DataTokens中添加一個(gè)Key為“UseNamespaceFallback”的條目表示是否采用后備命名空間對(duì)Controller類型進(jìn)行解析。如果注冊(cè)對(duì)象具有命名空間(調(diào)用MapRoute方法時(shí)指定了命名空間或者對(duì)應(yīng)的AreaRegistration類型定義在某個(gè)命名空間中),該條目的值為False;否則為True。該條目同樣反映在通過(guò)該Route對(duì)象生成的RouteData對(duì)象的DataTokens屬性中。[關(guān)于ASP.NET MVC路由,在我的文章《ASP.NET MVC路由擴(kuò)展:路由映射》中具有詳細(xì)的介紹]

在解析Controller真實(shí)類型的過(guò)程中,會(huì)先通過(guò)RouteData包含的命名空間來(lái)解析Controller類型。如果Controller類型解析失敗,則通過(guò)包含在通過(guò)RouteData的DataTokens屬性表示的RouteValueDictionary對(duì)象中的這個(gè)UseNamespaceFallback值來(lái)判斷是否使用“后備”命名空間進(jìn)行解析。具體來(lái)說(shuō),如果該值為True或者不存在,則先通過(guò)當(dāng)前ControllerBuilder的命名空間解析,如果失敗則忽略命名空間直接采用類型名稱進(jìn)行匹配;否則直接因找不到匹配的Controller而拋出異常。

我們通過(guò)具體的例子來(lái)說(shuō)明這個(gè)問(wèn)題。在一個(gè)通過(guò)Visual Studio的ASP.NET MVC項(xiàng)目創(chuàng)建的空Web應(yīng)用中,我們添加一個(gè)名稱為Admin的Area,此時(shí)IDE會(huì)默認(rèn)為我們添加如下一個(gè)AdminAreaRegistration類型。

   1: namespace Artech.MvcApp.Areas.Admin
   2: {
   3:     public class AdminAreaRegistration : AreaRegistration
   4:     {
   5:         public override string AreaName
   6:         {
   7:             get{return "Admin";}
   8:         }
   9:         public override void RegisterArea(AreaRegistrationContext context)
  10:         {
  11:             context.MapRoute("Admin_default", "Admin/{controller}/{action}/{id}",
  12:                 new { action = "Index", id = UrlParameter.Optional }
  13:             );
  14:         }
  15:     }
  16: }

AdminAreaRegistration類型定義在命名空間Artech.MvcApp.Areas.Admin中?,F(xiàn)在我們?cè)谠揂rea中添加一個(gè)Controller類,其名為HomeController。默認(rèn)情況下,我們添加的Controller類型和AdminAreaRegistration具有相同的命名空間,但是現(xiàn)在我們刻意將命名空間改為Artech.MvcApp.Areas。

  1. namespace Artech.MvcApp.Areas  
  2. {  
  3.     public class HomeController : Controller  
  4.     {  
  5.         public ActionResult Index()  
  6.         {  
  7.             return Content("...");  
  8.         }  
  9.     }  

現(xiàn)在我們?cè)跒g覽器中通過(guò)匹配的URL(/Admin/Home/Index)來(lái)訪問(wèn)Area為Admin的HomeController的Index操作,會(huì)得到如下圖所示的HTTP狀態(tài)為404的錯(cuò)誤。這就是因?yàn)樵趯?duì)Controller類型進(jìn)行解析的時(shí)候是嚴(yán)格按照對(duì)應(yīng)的AreaRegistration所在命名空間來(lái)進(jìn)行的,很顯然在這個(gè)范圍內(nèi)是不可能找得到對(duì)應(yīng)的Controller類型的。

image

四、Controller的激活與URL路由

ASP.NET路由系統(tǒng)是HTTP請(qǐng)求抵達(dá)服務(wù)端的***道屏障,它根據(jù)注冊(cè)的路由規(guī)則對(duì)攔截的請(qǐng)求進(jìn)行匹配并解析包含目標(biāo)Controller和Action名稱的路由信息。而當(dāng)前ControllerBuilder具有用于激活Controller對(duì)象的ControllerFactory,我們現(xiàn)在看看兩者是如何結(jié)合起來(lái)的。

通過(guò)《ASP.NET路由系統(tǒng)實(shí)現(xiàn)原理:HttpHandler的動(dòng)態(tài)映射》介紹我們知道ASP.NET路由系統(tǒng)的核心是一個(gè)叫做UrlRoutingModule的自定義HttpModule,路由的實(shí)現(xiàn)是它通過(guò)注冊(cè)代表當(dāng)前Web應(yīng)用的HttpApplication的PostResolveRequestCache事件對(duì)HttpHandler的動(dòng)態(tài)映射來(lái)實(shí)現(xiàn)的。具體來(lái)說(shuō),它通過(guò)以RouteTable的靜態(tài)屬性Routes代表的全局路由表對(duì)請(qǐng)求進(jìn)行匹配并得到一個(gè)RouteData對(duì)象。RouteData具有一個(gè)實(shí)現(xiàn)了接口IRouteHandler的屬性RouteHandler,通過(guò)該屬性的GetHttpHandler方法得到最終被映射到當(dāng)前請(qǐng)求的HttpHandler。

對(duì)于ASP.NET MVC應(yīng)用來(lái)說(shuō),RouteData的RouteHandler屬性類型為MvcRouteHandler,體現(xiàn)在MvcRouteHandler類型上關(guān)于HttpHandler的提供機(jī)制基本上(不是完全等同)可以通過(guò)如下的代碼來(lái)表示。MvcRouteHandler維護(hù)著一個(gè)ControllerFactory對(duì)象,該對(duì)象可以在構(gòu)造函數(shù)中指定,如果沒(méi)有顯示指定則直接通過(guò)調(diào)用當(dāng)前ControllerBuilder的GetControllerFactory方法獲取。

  1.  public class MvcRouteHandler : IRouteHandler  
  2.  {  
  3.      private IControllerFactory _controllerFactory;  
  4.       public MvcRouteHandler(): this(ControllerBuilder.Current.GetControllerFactory())  
  5.      { }  
  6.      public MvcRouteHandler(IControllerFactory controllerFactory)  
  7.     {  
  8.         _controllerFactory = controllerFactory;  
  9.     }  
  10.     IHttpHandler IRouteHandler.GetHttpHandler(RequestContext requestContext)  
  11.    {  
  12.        string controllerName = (string)requestContext.RouteData.GetRequiredString("controller");  
  13.        SessionStateBehavior sessionStateBehavior = _controllerFactory.GetControllerSessionBehavior(requestContext, controllerName);  
  14.         requestContext.HttpContext.SetSessionStateBehavior(sessionStateBehavior);  
  15.           return new MvcHandler(requestContext);  
  16.     }  
  17. }  

在用于提供HttpHandler的GetHttpHandler方法中,除了返回一個(gè)實(shí)現(xiàn)了IHttpHandler接口的MvcHandler對(duì)象之外,還需要對(duì)當(dāng)前HTTP上下文的會(huì)話狀態(tài)行為模式進(jìn)行設(shè)置。具體來(lái)說(shuō),首先通過(guò)包含在傳入RequestContext的RouteData對(duì)象得到Controller的名稱,該名稱連同RequestContext對(duì)象一起傳入ControllerFactory的GetControllerSessionBehavior方法得到一個(gè)類型為SessionStateBehavior的枚舉。***通過(guò)RequestContext得到表示當(dāng)前HTTP上下文的HttpContextBase對(duì)象(實(shí)際上是一個(gè)HttpContextWrapper對(duì)象)并調(diào)用其SetSessionStateBehavior方法。

紹我們知道RouteData中的RouteHandler屬性最初來(lái)源于對(duì)應(yīng)的Route對(duì)象的同名屬性,而當(dāng)我們調(diào)用RouteCollection的擴(kuò)展方法MapRoute方法時(shí),其內(nèi)部會(huì)直接創(chuàng)建并添加一個(gè)Route對(duì)象。由于在創(chuàng)建Route對(duì)象是并沒(méi)有顯式指定ControllerFactory,所以通過(guò)當(dāng)前ControllerBuilder的GetControllerFactory方法得到的ControllerFactory默認(rèn)被使用。

通過(guò)當(dāng)前ControllerBuilder的GetControllerFactory方法得到的ControllerFactory僅僅用于獲取會(huì)話狀態(tài)行為模式,而MvcHandler真正將它用于創(chuàng)建Controller。MvcHandler中關(guān)于對(duì)請(qǐng)求處理的邏輯基本上可以通過(guò)如下的代碼片斷來(lái)體現(xiàn)。如下面的代碼片斷所示,MvcHandler具有一個(gè)表示當(dāng)前請(qǐng)求上下文的RequestContext屬性,該屬性在構(gòu)造函數(shù)中被初始化。

  1. public class MvcHandler : IHttpHandler  
  2. {  
  3.     public RequestContext RequestContext { getprivate set; }  
  4.    public bool IsReusable  
  5.     {  
  6.         get { return false; }  
  7.     }  
  8.    public MvcHandler(RequestContext requestContext)  
  9.     {  
  10.        this.RequestContext = requestContext;  
  11.    }  
  12.    public void ProcessRequest(HttpContext context)  
  13.    {  
  14.        IControllerFactory controllerFactory = ControllerBuilder.Current.GetControllerFactory();  
  15.        string controllerName = this.RequestContext.RouteData.GetRequiredString("controller");  
  16.        IController controller = controllerFactory.CreateController(this.RequestContext, controllerName);  
  17.       try 
  18.        {  
  19.            controller.Execute(this.RequestContext);  
  20.        }  
  21.        finally 
  22.       {  
  23.           controllerFactory.ReleaseController(controller);  
  24.       }  
  25.    }  
  26. : } 

在ProcessRequest方法中,通過(guò)RequestContext對(duì)象得到目標(biāo)Controller的名稱,并通過(guò)它利用當(dāng)前ControllerBuilder創(chuàng)建的ControllerFactory激活Controller對(duì)象。在執(zhí)行了被激活Controller對(duì)象的Execute方法之后調(diào)用ControllerFactory的ReleaseController對(duì)其進(jìn)行釋放清理工作。

原文鏈接:http://www.cnblogs.com/artech/archive/2012/03/31/controller-activation-01.html

【編輯推薦】

  1. ASP.NET MVC3 從零開(kāi)始一步步構(gòu)建Web
  2. Node.js vs Opa: Web框架殺手
  3. 設(shè)計(jì)好脾氣的Web頁(yè)面
  4. Google Web App開(kāi)發(fā)指南之構(gòu)建優(yōu)秀的Web Apps
  5. 如何解決IndexedDB在webkit內(nèi)核下新舊版本的兼容問(wèn)題

 

責(zé)任編輯:彭凡 來(lái)源: 51CTO
相關(guān)推薦

2013-09-02 17:46:41

MVC架構(gòu)設(shè)計(jì)MVC架構(gòu)設(shè)計(jì)

2010-03-19 09:17:16

ASP.NET MVC

2023-07-03 08:48:40

Web模塊化設(shè)計(jì)

2009-09-18 10:20:26

PRG數(shù)據(jù)驗(yàn)證

2009-07-31 12:43:59

ASP.NET MVC

2011-04-18 09:35:59

ASP.NET MVC

2009-07-24 13:20:44

MVC框架ASP.NET

2009-10-29 09:15:32

ASP.NET MVCDropDownLis

2010-10-12 09:52:02

ASP.NET MVC

2009-07-24 11:55:29

ASP.NET MVC

2009-09-10 09:50:47

ASP.NET MVC

2009-12-11 09:36:50

ASP.NET MVC

2009-07-23 15:44:39

ASP.NET MVC

2009-07-22 10:09:59

ASP.NET MVC

2009-07-23 14:31:20

ASP.NET MVC

2009-07-22 13:24:24

ASP.NET MVC

2009-07-20 10:53:59

ASP.NET MVC

2010-01-26 13:15:42

ASP.NET MVC

2009-11-24 15:11:21

ASP.NET MVC

2010-02-03 09:50:58

ASP.NET MVC
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)