ASP.NET MVC Controller激活系統(tǒng)詳解:IoC的應(yīng)用[下篇]
[上篇]除了通過自定義ControllerFactory的方式引入IoC之外,在使用默認(rèn)DefaultControllerFactory情況下也可以通過一些擴(kuò)展使基于IoC的Controller激活成為可能。主要的方式就是自定義ControllerActivator和 DependencyResolver。
四、ControllerActivator V.S. DependencyResolver
如下面的代碼片斷所示,DefaultControllerFactory具有兩個(gè)構(gòu)造函數(shù)重載,其中一個(gè)具有一個(gè)類型為IControllerActivator接口的參數(shù),我們將實(shí)現(xiàn)了該接口得類型統(tǒng)稱為ControllerActivator。
1: public class DefaultControllerFactory : IControllerFactory
2: {
3: //其他成員
4: public DefaultControllerFactory();
5: public DefaultControllerFactory(IControllerActivator controllerActivator);
6: }
顧名思義,ControllerActivator就是Controller的“激活器”,Controller的激活實(shí)現(xiàn)在唯一的Create方法中。如下面的代碼所示,該方法具有兩個(gè)參數(shù)(requestContext和controllerType),分別代表當(dāng)前請(qǐng)求上下文和解析出來(lái)的目標(biāo)Controller的類型。
1: public interface IControllerActivator
2: {
3: IController Create(RequestContext requestContext, Type controllerType);
4: }
在默認(rèn)的情況下(調(diào)用DefaultControllerFactory默認(rèn)構(gòu)造函數(shù)或者指定的參數(shù)為Null),Controller激活系統(tǒng) 會(huì)默認(rèn)使用一個(gè)類型為DefaultControllerActivator的對(duì)象。如下面的代碼片斷所示,DefaultControllerActivator是一個(gè)實(shí)現(xiàn)了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的構(gòu)造函數(shù)具有一個(gè)類型為IDependencyResolver的參數(shù),這是一個(gè)重要的接口,我們將實(shí)現(xiàn)了該接口的類型統(tǒng)稱為DependencyResolver。。如下面的代碼片斷所示,IDependencyResolver接口具有兩個(gè)方法GetService和GetServices,用于根據(jù)指定的類型獲取單個(gè)或者多個(gè)實(shí)例。實(shí)際上DefaultControllerActivator就是通過調(diào)用GetService方法獲取具體的Controller對(duì)象的
1: public interface IDependencyResolver
2: {
3: object GetService(Type serviceType);
4: IEnumerable<object> GetServices(Type serviceType);
5: }
如果在構(gòu)造DefaultControllerActivator對(duì)象的時(shí)候傳入的參數(shù)為Null,那么Controller激活系統(tǒng)會(huì)使用通過DependencyResolver的靜態(tài)只讀屬性Current表示DependencyResolver。需要提醒的是,DependencyResolver類型沒有實(shí)現(xiàn)IDependencyResolver接口,而是對(duì)一個(gè)實(shí)現(xiàn)了IDependencyResolver接口類型對(duì)象的封裝。
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: }
這個(gè)被封裝的DependencyResolver(指實(shí)現(xiàn)了接口IDependencyResolver的某個(gè)類型的類型,不是指DependencyResolver類型的對(duì)象,對(duì)于后者我會(huì)采用“DependencyResolver類型對(duì)象”的說(shuō)法)通過只讀屬性InnerCurrent表示,而三個(gè)InnerSetResolver方法重載用于初始化改屬性。靜態(tài)字段_instance表示當(dāng)前的DependencyResolver類型對(duì)象,靜態(tài)只讀屬性Current則表示該對(duì)象內(nèi)部封裝的DependencyResolver對(duì)象,而它通過三個(gè)靜態(tài)的SetResolver進(jìn)行初始化。
如果我們不曾通過調(diào)用DependencyResolver的靜態(tài)方法SetResolver通過Current屬性表示的當(dāng)前DependencyResolver進(jìn)行顯示設(shè)置,該屬性默認(rèn)返回一個(gè)DefaultDependencyResolver對(duì)象。如下面的代碼片斷所示,DefaultDependencyResolver是一個(gè)實(shí)現(xiàn)了IDependencyResolver接口的私有類型,在實(shí)現(xiàn)的GetService方法中,它直接通過根據(jù)指定的類型以反射的形式創(chuàng)建相應(yīng)的對(duì)象并返回,所以前面我們說(shuō)DefaultControllerFactory根據(jù)解析出來(lái)的Controller類型以反射的形式創(chuàng)建對(duì)應(yīng)的實(shí)例在這里得到了印證。至于GetServices方法則返回一個(gè)空對(duì)象集合。
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之前的關(guān)系基本上可以通過如下圖所示的類圖來(lái)體現(xiàn)。
五、通過自定義ControllerActivator實(shí)現(xiàn)IoC
如果我們基于一個(gè)ControllerActivator對(duì)象來(lái)創(chuàng)建一個(gè)DefaultControllerFactory,它會(huì)最終被用于Controller對(duì)象的激活,那么我們可以自定義ControllerActivator的方式將IoC引入Controller激活系統(tǒng)。我們接下來(lái)自定義的ControllerActivtor基于另一個(gè)IoC框架Ninject,較之Unity,Ninject是一個(gè)更加輕量級(jí)也更適合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: }
我們使用的還是上面演示的關(guān)于員工管理的例子。NinjectControllerActivator的只讀屬性Kernel在這里用于類型注冊(cè)和基于類型的實(shí)例提供,具體來(lái)說(shuō)它是在構(gòu)造函數(shù)中初始化的StandardKernel對(duì)象。同樣在構(gòu)造函數(shù)中,我們通過該Kernel實(shí)現(xiàn)了作為Model接口的IEmployeeRepository類型和Model實(shí)現(xiàn)的EmployeeRepository類型之間的映射。在Create方法中,我們通過Kernel的TryGet方法根據(jù)指定的類型獲取相應(yīng)的Controller對(duì)象。
現(xiàn)在我們無(wú)須再使用自定義的ControllerFactory,只需要注冊(cè)一個(gè)基于我們自定義的NinjectControllerActivator的DefaultControllerFactory即可。定義在Global.asax中與ControllerFactory注冊(cè)相關(guān)的代碼如下所示。
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實(shí)現(xiàn)IoC
通過前面的介紹我們知道,當(dāng)我們調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)DefaultControllerFactory的時(shí)候,如果調(diào)用的時(shí)候默認(rèn)無(wú)參構(gòu)造函數(shù),后者將作為參數(shù)的ControllerActivator對(duì)象設(shè)置為Null,那么默認(rèn)請(qǐng)求用于激活Controller實(shí)例的是通過DependencyResoolver類型的靜態(tài)屬性Current表示的DependencyResoolver對(duì)象。換言之,我們可以通過自定義DependencyResoolver的方式來(lái)實(shí)現(xiàn)基于IoC的Controller激活。
同樣是采用Ninject,我們定義了一個(gè)具有如下定義的NinjectDependencyResolver。與上面定義的NinjectControllerActivator類似,NinjectDependencyResolver具有一個(gè)IKernel類型的只讀屬性Kernel,該屬性在構(gòu)造函數(shù)中被初始化。同樣是在構(gòu)造函數(shù)中,我們通過該Kernel完成了IEmployeeRepository接口和EmployeeRepository類型的注冊(cè)。對(duì)于實(shí)現(xiàn)的GetService和GetServices方法,我們直接調(diào)用Kernel的TryGet和GetAll返回指定類型的實(shí)例和實(shí)例列表。[源代碼從這里下載]
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: }
由于默認(rèn)情況下通過無(wú)參構(gòu)造函數(shù)創(chuàng)建的DefaultConrtollerFactory會(huì)被使用,所以我們無(wú)須進(jìn)行ControllerFactory的注冊(cè)。我們只需要?jiǎng)?chuàng)建一個(gè)自定義的NinjectDependencyResolver對(duì)象并將其作為當(dāng)前的DependencyResolver即可,定義在Global.asax設(shè)置當(dāng)前DependencyResolver的代碼如下所示。
1: public class MvcApplication : System.Web.HttpApplication
2: {
3: //其他成員
4: protected void Application_Start()
5: {
6: //其他操作
7: DependencyResolver.SetResolver( new NinjectDependencyResolver());
8: }
9: }


除了通過自定義ControllerFactory的方式引入IoC之外,在使用默認(rèn)DefaultControllerFactory情況下也可以通過一些擴(kuò)展使基于IoC的Controller激活成為可能。主要的方式就是自定義ControllerActivator和 DependencyResolver。

浙公網(wǎng)安備 33010602011771號(hào)