ASP.NET MVC Controller激活系統詳解:IoC的應用[下篇]


[上篇]除了通過自定義ControllerFactory的方式引入IoC之外,在使用默認DefaultControllerFactory情況下也可以通過一些擴展使基於IoC的Controller激活成為可能。主要的方式就是自定義ControllerActivator和 DependencyResolver。

四、ControllerActivator V.S. DependencyResolver

如下面的代碼片斷所示,DefaultControllerFactory具有兩個構造函數重載,其中一個具有一個類型為IControllerActivator接口的參數,我們將實現了該接口得類型統稱為ControllerActivator。

   1: public class DefaultControllerFactory : IControllerFactory
   2: {
   3:     //其他成員
   4:     public DefaultControllerFactory();
   5:     public DefaultControllerFactory(IControllerActivator controllerActivator);   
   6: }

顧名思義,ControllerActivator就是Controller的“激活器”,Controller的激活實現在唯一的Create方法中。如下面的代碼所示,該方法具有兩個參數(requestContext和controllerType),分別代表當前請求上下文和解析出來的目標Controller的類型。

   1: public interface IControllerActivator
   2: {
   3:     IController Create(RequestContext requestContext, Type controllerType);
   4: }

在默認的情況下(調用DefaultControllerFactory默認構造函數或者指定的參數為Null),Controller激活系統 會默認使用一個類型為DefaultControllerActivator的對象。如下面的代碼片斷所示,DefaultControllerActivator是一個實現了IControllerActivator私有類型而已,我們不能直接通過編程的方式使用它。

   1: private class DefaultControllerActivator : IControllerActivator
   2: {
   3:     public DefaultControllerActivator();
   4:     public DefaultControllerActivator(IDependencyResolver resolver);
   5:      public IController Create(RequestContext requestContext,  Type controllerType);
   6: }

DefaultControllerActivator的構造函數具有一個類型為IDependencyResolver的參數,這是一個重要的接口,我們將實現了該接口的類型統稱為DependencyResolver。。如下面的代碼片斷所示,IDependencyResolver接口具有兩個方法GetService和GetServices,用於根據指定的類型獲取單個或者多個實例。實際上DefaultControllerActivator就是通過調用GetService方法獲取具體的Controller對象的

   1: public interface IDependencyResolver
   2: {
   3:     object GetService(Type serviceType);
   4:     IEnumerable<object> GetServices(Type serviceType);
   5: }

如果在構造DefaultControllerActivator對象的時候傳入的參數為Null,那么Controller激活系統會使用通過DependencyResolver的靜態只讀屬性Current表示DependencyResolver。需要提醒的是,DependencyResolver類型沒有實現IDependencyResolver接口,而是對一個實現了IDependencyResolver接口類型對象的封裝。

   1: public class DependencyResolver
   2: {
   3: private static DependencyResolver _instance;
   4:  
   5:     public void InnerSetResolver(object commonServiceLocator);
   6:     public void InnerSetResolver(IDependencyResolver resolver);
   7:     public void InnerSetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices);
   8:     
   9:     public static void SetResolver(object commonServiceLocator);
  10:     public static void SetResolver(IDependencyResolver resolver);
  11:     public static void SetResolver(Func<Type, object> getService, Func<Type, IEnumerable<object>> getServices);
  12:  
  13:     public static IDependencyResolver Current { get; }
  14:     public IDependencyResolver InnerCurrent { get; }
  15: }

這個被封裝的DependencyResolver(指實現了接口IDependencyResolver的某個類型的類型,不是指DependencyResolver類型的對象,對於后者我會采用“DependencyResolver類型對象”的說法)通過只讀屬性InnerCurrent表示,而三個InnerSetResolver方法重載用於初始化改屬性。靜態字段_instance表示當前的DependencyResolver類型對象,靜態只讀屬性Current則表示該對象內部封裝的DependencyResolver對象,而它通過三個靜態的SetResolver進行初始化。

如果我們不曾通過調用DependencyResolver的靜態方法SetResolver通過Current屬性表示的當前DependencyResolver進行顯示設置,該屬性默認返回一個DefaultDependencyResolver對象。如下面的代碼片斷所示,DefaultDependencyResolver是一個實現了IDependencyResolver接口的私有類型,在實現的GetService方法中,它直接通過根據指定的類型以反射的形式創建相應的對象並返回,所以前面我們說DefaultControllerFactory根據解析出來的Controller類型以反射的形式創建對應的實例在這里得到了印證。至於GetServices方法則返回一個空對象集合。

   1: private class DefaultDependencyResolver : IDependencyResolver
   2: {
   3:     public object GetService(Type serviceType)    
   4:     {
   5:         if (serviceType.IsInterface || serviceType.IsAbstract)
   6:         {
   7:             return null;
   8:         }
   9:         try
  10:         {
  11:             return Activator.CreateInstance(serviceType);
  12:         }
  13:         catch
  14:         {
  15:             return null;
  16:         }
  17:     }
  18:  
  19:     public IEnumerable<object> GetServices(Type serviceType)
  20:     {
  21:         return Enumerable.Empty<object>();
  22:     }
  23: }

上面介紹的類型DefaultControllerFactory、IControllerActivator、DefaultControllerActivator、IDependencyResolver、DefaultDependencyResolver和DependencyResolver之前的關系基本上可以通過如下圖所示的類圖來體現。

image

五、通過自定義ControllerActivator實現IoC

如果我們基於一個ControllerActivator對象來創建一個DefaultControllerFactory,它會最終被用於Controller對象的激活,那么我們可以自定義ControllerActivator的方式將IoC引入Controller激活系統。我們接下來自定義的ControllerActivtor基於另一個IoC框架Ninject,較之Unity,Ninject是一個更加輕量級也更適合ASP.NET MVC的IoC框架。我們將自定義的ControllerActivator起名為NinjectControllerActivator,全部定義如下。[源代碼從這里下載]

   1: public class NinjectControllerActivator: IControllerActivator
   2: {
   3:     public IKernel Kernel { get; private set; }
   4:     public NinjectControllerActivator()
   5:     {
   6:         this.Kernel = new StandardKernel();
   7:         AddBindings();    
   8:     }    
   9:     public IController Create(RequestContext requestContext, Type controllerType)
  10:     {
  11:         return (IController)this.Kernel.TryGet(controllerType) as IController;
  12:     }
  13:     private void AddBindings()
  14:     {
  15:         this.Kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
  16:     }
  17: }

我們使用的還是上面演示的關於員工管理的例子。NinjectControllerActivator的只讀屬性Kernel在這里用於類型注冊和基於類型的實例提供,具體來說它是在構造函數中初始化的StandardKernel對象。同樣在構造函數中,我們通過該Kernel實現了作為Model接口的IEmployeeRepository類型和Model實現的EmployeeRepository類型之間的映射。在Create方法中,我們通過Kernel的TryGet方法根據指定的類型獲取相應的Controller對象。

現在我們無須再使用自定義的ControllerFactory,只需要注冊一個基於我們自定義的NinjectControllerActivator的DefaultControllerFactory即可。定義在Global.asax中與ControllerFactory注冊相關的代碼如下所示。

   1: public class MvcApplication : System.Web.HttpApplication
   2: {
   3:     //其他成員
   4:     protected void Application_Start()
   5:     {
   6:         //其他操作
   7:         NinjectControllerActivator controllerActivator =  new NinjectControllerActivator();
   8:         DefaultControllerFactory controllerFactory  = new DefaultControllerFactory(controllerActivator);
   9:         ControllerBuilder.Current.SetControllerFactory(controllerFactory);
  10:     }
  11: }

六、通過自定義DependencyResoolver實現IoC

通過前面的介紹我們知道,當我們調用構造函數創建一個DefaultControllerFactory的時候,如果調用的時候默認無參構造函數,后者將作為參數的ControllerActivator對象設置為Null,那么默認請求用於激活Controller實例的是通過DependencyResoolver類型的靜態屬性Current表示的DependencyResoolver對象。換言之,我們可以通過自定義DependencyResoolver的方式來實現基於IoC的Controller激活。

同樣是采用Ninject,我們定義了一個具有如下定義的NinjectDependencyResolver。與上面定義的NinjectControllerActivator類似,NinjectDependencyResolver具有一個IKernel類型的只讀屬性Kernel,該屬性在構造函數中被初始化。同樣是在構造函數中,我們通過該Kernel完成了IEmployeeRepository接口和EmployeeRepository類型的注冊。對於實現的GetService和GetServices方法,我們直接調用Kernel的TryGet和GetAll返回指定類型的實例和實例列表。[源代碼從這里下載]

   1: public class NinjectDependencyResolver : IDependencyResolver
   2: {
   3:     public IKernel Kernel { get; private set; }
   4:     public NinjectDependencyResolver()
   5:     {
   6:         this.Kernel = new StandardKernel();
   7:         AddBindings();
   8:     }
   9:     private void AddBindings()
  10:     {
  11:         this.Kernel.Bind<IEmployeeRepository>().To<EmployeeRepository>();
  12:     }
  13:  
  14:     public object GetService(Type serviceType)
  15:     {
  16:         return this.Kernel.TryGet(serviceType);
  17:     }
  18:  
  19:     public IEnumerable<object> GetServices(Type serviceType)
  20:     {
  21:         return this.Kernel.GetAll(serviceType);
  22:     }
  23: }

由於默認情況下通過無參構造函數創建的DefaultConrtollerFactory會被使用,所以我們無須進行ControllerFactory的注冊。我們只需要創建一個自定義的NinjectDependencyResolver對象並將其作為當前的DependencyResolver即可,定義在Global.asax設置當前DependencyResolver的代碼如下所示。

   1: public class MvcApplication : System.Web.HttpApplication
   2: {
   3:     //其他成員
   4:     protected void Application_Start()
   5:     {
   6:         //其他操作
   7:         DependencyResolver.SetResolver( new NinjectDependencyResolver());
   8:     }
   9: }
 
ASP.NET MVC Controller激活系統詳解:總體設計
ASP.NET MVC Controller激活系統詳解:默認實現
ASP.NET MVC Controller激活系統詳解:IoC的應用[上篇]
ASP.NET MVC Controller激活系統詳解:IoC的應用[下篇]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM