Artech 已经写过一篇[原创]WCF后续之旅(7):通过WCF Extension实现和Enterprise Library Unity Container的集成,在这个解决方案中Unity的侵入性有点强,本文介绍一种具有更少的侵入性的解决方案。 第一步:创建一个自定义的InstanceProvider 来处理WCF服务。 InstanceProvider就是用于创建或者提供service instance的。除了提供service instance的创建者或者提供者的身份外,InstanceProvider还用于service instance的释放和回收。所有的IntanceProvider实现了 System.ServiceModel.Dispatcher.IInstanceProvider 接口: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Practices.Unity; using System.ServiceModel.Dispatcher; using System.ServiceModel; using System.ServiceModel.Channels; namespace Tencent.OA.Framework.ServiceModel { public class UnityInstanceProvider : IInstanceProvider { public UnityContainer Container { set; get; } public Type ServiceType { set; get; } public UnityInstanceProvider() : this(null) { } public UnityInstanceProvider(Type type) { ServiceType = type; Container = new UnityContainer(); } #region IInstanceProvider Members public object GetInstance(InstanceContext instanceContext, Message message) { return Container.Resolve(ServiceType); } public object GetInstance(InstanceContext instanceContext) { return GetInstance(instanceContext, null); } public void ReleaseInstance(InstanceContext instanceContext, object instance) { } #endregion } } 可以看到GetInstance方法用来获取服务实例,通过Unity的Resolve方法解析。 第二步:创建UnityInstanceProvider对应的Behavior 第一步已经创建了自定义的UnityInstanceProvider,现在需要在运行时插入我们这个新的Provider,这项工作可以通过IServiceProvider(定义一种检索服务对象的机制,服务对象是为其他对象提供自定义支持的对象)来完成。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel.Dispatcher; using System.ServiceModel.Description; using System.ServiceModel; using System.Collections.ObjectModel; using System.ServiceModel.Channels; using Microsoft.Practices.Unity; namespace Tencent.OA.Framework.ServiceModel { public class UnityServiceBehavior : IServiceBehavior { public UnityInstanceProvider InstanceProvider { get; set; } private ServiceHost serviceHost = null; public UnityServiceBehavior() { InstanceProvider = new UnityInstanceProvider(); } public UnityServiceBehavior(UnityContainer unity) { InstanceProvider = new UnityInstanceProvider(); InstanceProvider.Container = unity; } public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers) { ChannelDispatcher cd = cdb as ChannelDispatcher; if (cd != null) { foreach (EndpointDispatcher ed in cd.Endpoints) { InstanceProvider.ServiceType = serviceDescription.ServiceType; ed.DispatchRuntime.InstanceProvider = InstanceProvider; } } } } public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase) { } public void AddBindingParameters(ServiceDescription serviceDescription,ServiceHostBase serviceHostBase,Collection endpoints, BindingParameterCollection bindingParameters) { } } } 当调用ApplyDispatchBehaviour,代码通过循环收集在我们的项目Endpoints,并传递给相应的服务类型的InstanceProvider。 第三步:创建自定义的增加新的Behavior的 Service Host ServiceHost 提供了基本的“加载服务,配置endpoints,应用安全设置以及启动监听请求”机制。通过自定义一个ServiceHost将我们自己的Behavior添加进去。 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using Microsoft.Practices.Unity; namespace Tencent.OA.Framework.ServiceModel { public class UnityServiceHost : ServiceHost { public UnityContainer Container { set; get; } public UnityServiceHost() : base() { Container = new UnityContainer(); } public UnityServiceHost(Type serviceType, params Uri[] baseAddresses)
{ Container = new UnityContainer(); } protected override void OnOpening() { if (this.Description.Behaviors.Find() == null) this.Description.Behaviors.Add(new UnityServiceBehavior(Container)); base.OnOpening(); } } } 当Service Host启动的时候,它就会检查我们的UnityServiceBehavior是否已经添加到Behaviors里面,如果没有就把它加入到Behaviors集合。 第四步:创建自定义的ServiceHostFactory 如果只是承载在Console Application、Windows Service或者其他非Web应用程序,我们的工作已经完成了。但在Web的.svc中,ServiceHost是动态创建的,没有显示的指定 ServiceHost的Factory,那它在默认情况下是使用ServiceHostFactory的,而ServiceHostFactory产生 的是ServiceHost对象,想要使用我们上一步中自定义的UnityServiceHost ,需要实现一个自定义的ServcieHostFactory,实现代码非常简单: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Microsoft.Practices.Unity.Configuration; using Microsoft.Practices.Unity; using System.ServiceModel.Activation; using System.ServiceModel; using System.Configuration; namespace Tencent.OA.Framework.ServiceModel { public class UnityServiceHostFactory : ServiceHostFactory { protected override ServiceHost CreateServiceHost( Type serviceType, Uri[] baseAddresses) { UnityServiceHost serviceHost = new UnityServiceHost(serviceType, baseAddresses); UnityContainer container = new UnityContainer(); serviceHost.Container = container; //configure container UnityConfigurationSection section = (UnityConfigurationSection)ConfigurationManager.GetSection("unity"); section.Containers.Default.Configure(serviceHost.Container); return serviceHost; } }