4.Controller默认激活
Controller对象的激活最终是通过注册的ControllerFactory完成的,当我们没有显示调用ControllerBuilder的SetControllerFactory方法指定ControllerFactory对象时,Controller激活系统会使用一个DefaultControllerFactory对象来激活目标Controller,这就是ASP.NET MVC采用的默认Controller激活机制。
目标Controller对象被激活的前提是得到目标Controller的真实类型,在DefaultControllerFactory里包括了解析Controller类型的一些路由信息,比如Controller的名称,命名空间,当前ControllerBuilder的默认命名空间等。大家可能感觉有了这3个条件,应该就可以通过名称拿到Controller实例,然而这不可以。首先,在RouteData里的Controller名称的变量值是不区分大小写的,而类型名称则是对大小写敏感的;对于命名空间,通过前面的学习了解到一般都是在名称后加一个.*;因此我们无法通过名称去解析目标Controller的类型了。正确的做法是DefaultControllerFactory先调用BuildManager的静态方法GetReferencedAssemblies得到所有可用的程序集,再从中挑选所有实习了接口IController的类型,最后通过Controller名称和命名空间去与目标名称匹配,简单点说,后者的方式保证了目标Controller和命名空间没有改动过,是最真实的数据。
出于对性能的考虑,对于解析出来的所有有效的Controller类型作了全局缓存。针对Controller类型的缓存同样实现在DefaultControllerFactory里,而且这个列表是持久化的,即应用重启后仍然存在。用于激活目标Controller对象的ControllerFactory不仅仅用于创建目标Controller对象,还有2个功能:一个是对激活的Controller对象进行释放和回收,另一个则是通过GetControllerSessionBehavior方法返回控制当前会话状态行为的SessionStateBehavior枚举对象。
5.Ioc应用
控制反转,简称Ioc。以前学MVC时听老师讲过这个词,不过没怎么深刻体会这个词,今天我要征服它。Ioc的意思简单点是应用本身不负责依赖对象的创建和维护,而将这个任务交给外部容器,这样应用权就由应用转移到了这个外部Ioc容器,这样控制权就实现了反转,也就是说,控制反转是控制权被反过来给别人了。比如A类需要使用B类的实例,而B实例的创建并不由A来负责,而是通过外部容器来创建。这种思想在实现针对目标Controller的激活具有重要的意义。
Ioc和DI(依赖注入)往往联系在一起。DI就是由外部容器在运行时动态地将依赖的对象注入到组件之中。书作者蒋先生比较喜欢将依赖注入分为一种映射和3种注入,我感觉理解起来很不错。
(1)映射是类型映射,虽然我们可以通过接口或者抽象类来调用某个对象的方法,但是对象本身是一个具体的类型,所以需要某种类型注册机制来解决接口/抽象类和实现类/具体子类之间的匹配关系。
(2)构造器注入,Ioc容器会智能地选择和调用合适的构造函数来创建依赖的对象。如果被选择的构造函数具有相应的参数,Ioc容器会在调用构造函数之前解析注册的依赖关系并自行创建相应的参数对象。
(3)属性注入,如果需要使用到被依赖对象的某个属性,在被依赖对象被创建之后Ioc会自动初始化该属性。
(4)方法注入,如果被依赖对象需要调用某个方法进行相应的初始化,在该对象被创建之后Ioc容器会自动调用该方法。下面来看一个例子,
public interface IA { } public interface IB { } public interface IC { } public interface ID { } public class A : IA { public IB B { get; set; } public ID D { get; set; } //构造器注入 public A(IB b) { this.B = b; } //属性注入 public IC c; public IC C { get { return c; } set { c = value; } } //方法注入 public void Initialize(ID d) { } }
我们知道用户请求过来时,如果涉及到数据业务,Controller会直接调用Model,如果需要呈现业务数据,则会将相应的数据转为ViewModel,此时Controller对Model是直接依赖的。现在可以将Ioc的思想应用到Controller激活系统中,如果采用Ioc的方式提供用于被处理请求的Controller对象,那么Controller和Model之间的依赖程度会被降低。我们还可以定义IModel接口,以这种方式对Model进行抽象,让Controller依赖于这个抽象化Model接口,而不是具体的Model实现。