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<ServiceEndpoint> 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)
??????????? : base(serviceType, baseAddresses)
??????? {
??????????? Container = new UnityContainer();
??????? }
??????? protected override void OnOpening()
??????? {
??????????? if (this.Description.Behaviors.Find<UnityServiceBehavior>() == 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;
??????? }
??? }
}