介绍
ASP.NET MVC3 的一个重要的新特性就是允许注册一个服务点 Service Location,然后在框架中使用的能力。以前版本的 MVC 已经提供了 Service Location 和依赖注入的机会,在 MVC3 中,我们正式提供了这种能力,并且为开发者开放了多种使用的机会。总体策略
关于 Service Location 的最重要的部分就是它是可选的,这意味着如果你对 Service Location 不感兴趣,那么,你不需要被强制使用,你总是可以在不使用 Service Location 的情况下,调用自定义的函数。在以后加入新的 Service Location 的时候,也会保持向后的兼容性。当使用注册的 Service Location 的时候,依赖于具体的使用,MVC 一般将会使用下面三种策略之一:
1. 定位一个唯一的注册服务
现在的 MVC 中使用的许多服务都注册一个实例来提供服务,例如,控制器工厂 Controller Factory,它实现了接口 IControllerFactory。对于整个应用来说,只有一个控制器工厂实例。
当 MVC 试图使用单个的注册服务的时候,它将会首先通过 Service Locator 寻找时候存在一个注册的服务实例,如果有,将使用这个服务实例,如果没有,那么将会回退到没有使用服务定位器时候注册的单个实例。
上面的处理顺序意味着使用服务定位器的用户不必担心现存项目中 MVC 的默认服务。因为当服务提供器不存在的时候,将会自动使用原来注册的服务,这种潜力也意味着可以在两个地方注册自定义的服务,但是只有通过服务器注册的服务被使用。
2. 定位多个注册的服务
在 MVC 中也有为一个服务注册多个服务实例的地方,比如说,视图引擎,视图引擎实现了接口 IViewEngine,典型情况下,MVC 提供了注册多个服务的注册点,也提供了 ViewEngines.Engines 来找到每一个视图引擎,并确定其中之一可以提供服务。还有其他的类似的场合,比如, ModelValidatorProviders.Providers 。
当 MVC 试图使用这种具有多个服务实例的服务的时候,MVC 将会通过管理多个服务实现的 Facade 来完成,Facade 将会把通过静态注册的服务实例和通过 Service Location 注册的服务实例结合在一起来选择合适的实现。在这里,服务的顺序是很重要的,通常意味着通过 Service Location 注册的服务实例要优先静态注册的实例。
类似于单实例服务注册,这意味着对于存在默认服务提供器的时候,不需要再通过 Service Location 来注册服务,这也意味着对于注册的多个服务来说,多数的容器也不必提供一个本地的排序函数,因为如果顺序是重要的,就可能需要非 Service Location 的 API。
3. 创建对象
MVC 使用服务定位器最后的策略就是直接创建对象,这最好通过依赖注入的服务来实现,我们将试图通过 Service Location 来创建对象,一个典型的例子就是控制器对象 Controller。
当 MVC 试图创建新的对象的时候,它将会请求服务定位器来创建这个对象,如果服务定位器不能完成这个任务,那么,将会回退到 MVC2 的行为,通常意味着使用 Activator.CreateInstance 来创建。
IDependencyResolver
为了在 MVC3 中使用服务定位,在 MVC3 中提供了一个接口 IDependencyResolver 和一个新的类 DependencyResolver,1 public interfac IDependencyResolver
2 {
3 object GetService( Type serviceType );
4 IEnumerable<object> GetServices( Type serviceType );
5 }
DependencyResolver 的定义如下:
public class DependencyResolver
{
public static IDependencyResolver Current { get; }
public static void SetResolver( Object commonServiceLocator );
public static void SetResolver( IDependencyResolver resolver );
public static void SetResolver( Func<Type, Object> getService, Func<Type, Enumerable<Object>> getServices );
}
三个静态方法提供了注册服务定位器的机制,静态属性 Current 用来获取注册的服务点。
Common Service Locator 提供了一个可以在应用程序或者框架中使用的共享的服务点,同时,项目中也提供了对于常见 IoC 的包装。
Service locator adapter implementations
ImplementationCastle Windsor Adapter
Spring .NET Adapter
Unity Adapter
StructureMap Adapter
Autofac Adapter
MEF Adapter now _disibledevent=>LinFu Adapter
Multi-target CSL binaries
示例
例如,在程序中我们定义了如下的接口用于获取信息。并提供了两种实现方式:Hello 和 Hi。namespace mvc_1.study
{
public interface IHello
{
string Message { get; }
}
public class Hello : IHello
{
public string Message
{
get { return "Hello, world."; }
}
}
public class Hi : IHello
{
public string Message
{
get { return "世界,你好!"; }
}
}
}
项目中使用 Unity 来作为实际的 IoC 容器。类型注册通过配置文件完成。
<configuration>
<configSections>
<section
name="unity"
type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
</configSections>
<unity>
<typeAliases>
<typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
<typeAlias alias="external" type="Microsoft.Practices.Unity.ExternallyControlledLifetimeManager, Microsoft.Practices.Unity" />
<typeAlias alias="perThread" type="Microsoft.Practices.Unity.PerThreadLifetimeManager, Microsoft.Practices.Unity" />
</typeAliases>
<containers>
<container>
<types>
<type type="mvc_1.study.IHello,StudyModel"
mapTo="mvc_1.study.Hi,StudyModel" >
<lifetime type="singleton" />
</type>
</types>
</container>
</containers>
</unity>
<configuration>
在程序中,我们可以使用类似于下面的代码来注册服务点。
// 创建 Unity 容器
IUnityContainer container = new Microsoft.Practices.Unity.UnityContainer();
// 读取配置文件
Microsoft.Practices.Unity.Configuration.UnityConfigurationSection
config
= System.Configuration.ConfigurationManager
.GetSection("unity")
as UnityConfigurationSection;
// 通过配置文件设置容器
config.Configure(container);
// 在代码中直接注册,一般不用
// container.RegisterType<mvc_1.study.IHello, mvc_1.study.Hello>();
// 包装为 ServiceLocator
Microsoft.Practices.Unity.ServiceLocatorAdapter.UnityServiceLocator locator
= new Microsoft.Practices.Unity.ServiceLocatorAdapter.UnityServiceLocator(container);
// 注册
DependencyResolver.SetResolver(locator);
在代码中,可以直接通过服务点来获取注册的对象实例。
mvc_1.study.IHello hello
= DependencyResolver.Current.GetService<mvc_1.study.IHello>();
return hello.Message;
关于 unity 容器,可以参考
Enterprise Library - Unity Application Block 学习手册(最新版) Part 1
的 你知道Unity IoC Container是如何创建对象的吗?
最新评论