在《原理篇》中我们谈到了通过自定义ServiceHost对WCF进行扩展的本质,以及在IIS/WAS寄宿情况下ServiceHostFactory的作用。接下来通过一个具体的例子来演示如何通过WCF扩展实现以Unity为代表的IoC框架的集成,以及应用该扩展的ServiceHost和ServiceHostFactory如何定义。[源代码从这里下载]
目录
一、IoC/DI简介
步骤一、自定义InstanceProvider:UnityInstanceProvider
步骤二、创建服务行为:UnityServiceBehaviorAttribute
步骤三、自定义ServiceHost:UnityServiceHost
步骤四、自定义ServiceHostFactory:UnityServiceHostFactory
步骤五、创建实例程序应用自定义ServiceHost
一、IoC/DI简介
所谓控制反转(IoC: Inversion Of Control)就是应用本身不负责依赖对象的创建和维护,而交给一个外部容器来负责。这样控制权就由应用转移到了外部IoC容器,控制权就实现了所谓的反转。比如,在类型A中需要使用类型B的实例,而B实例的创建并不由A来负责,而是通过外部容器来创建。
有时我们又将IoC成为依赖注入(DI: Dependency Injection)。所谓依赖注入,就是由外部容器在运行时动态地将依赖的对象注入到组件之中。具体的依赖注入方式又包括如下三种典型的形式。
- 构造器注入(Constructor Injection):IoC容器会智能地选择选择和调用适合的构造函数以创建依赖的对象。如果被选择的构造函数具有相应的参数,IoC容器在调用构造函数之前会自定义创建相应参数对象;
- 属性注入(Property Injection):如果需要使用到被依赖对象的某个属性,在被依赖对象被创建之后,IoC容器会自动初始化该属性;
- 方法注入(Method Injection):如果被依赖对象需要调用某个方法进行相应的初始化,在该对象创建之后,IoC容器会自动调用该方法。
在开源社区,具有很有流行的IoC框架,比如Castle Windsor、Unity、Spring.NET、StructureMap、Ninject等。现在我们就以Unity为例,介绍通过WCF的扩展如何实现基于IoC的服务实例的创建。
要实现WCF和Unity之间的集成,最终体现在如何通过Unity容器来创建服务实例。而从前面介绍的关于服务端运行时框架的介绍,我们知道最终服务实例的提供落在了一个特殊的组件之上,即InstanceProvider。所以,本实例的核心就是要自定义一个采用Unity实现服务实例提供机制的自定义InstanceProvider。我们将之命名为UnityInstanceProvider。
下面的代码给出了实现IInstanceProvider接口的UnityInstanceProvider的定义。在构造函数中指定连个参数:实现了IUnityContainer接口的Unity容器对象和服务契约类型。那么在真正实现对服务实例创建的GetInstance方法上,直接调用IUnityContainer的Resolve方法传入给定的服务契约类型来创建具体的人服务实例。而在ReleaseInstance方法中则直接调用IUnityContainer的Teardown方法进行服务实例的释放。注意,在这之前需要确保如下两个基于Unity的程序集被引用:Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll。
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Dispatcher;
using Microsoft.Practices.Unity;
namespace Artech.WcfExtensions.IoC
7: {
class UnityInstanceProvider: IInstanceProvider
9: {
private set; }
private set; }
12:
public UnityInstanceProvider(IUnityContainer unityContainer, Type contractType)
14: {
this.UnityContainer = unityContainer;
this.ContractType = contractType;
17: }
18:
object GetInstance(InstanceContext instanceContext, Message message)
20: {
this.ContractType);
22: }
23:
object GetInstance(InstanceContext instanceContext)
25: {
null);
27: }
28:
object instance)
30: {
this.UnityContainer.Teardown(instance);
32: }
33: }
34: }