WCF服务属性注入基础设施
WCF的服务的创建行为:使用默认构造函数创建WCF服务对象。如果我们想要在WCF内使用外部对象,最简单的方式就是把外部对象做成全局对象。然而这样的话会增加全局对象的数量,让代码的耦合度增加了。所以,我们需要突破WCF的默认行为。解决的办法是添加自定义的ServiceHost子类。
首先,添加一个IWCFService泛型接口,WCF服务将继承这个接口,从而拥有外部注入泛型属性的能力。
public interface IWCFService<TDependency> { TDependency Dependency { get ; set ; } } |
其次,我们需要自定义ServiceHost子类,提供外部注入Dependency的构造函数。
public class WCFServiceHost<Service, TDependency> : ServiceHost where Service : IWCFService<TDependency>, new () { public WCFServiceHost(TDependency dependency, Type serviceType, params Uri[] baseAddresses) : base (serviceType, baseAddresses) { if (dependency == null ) { throw new ArgumentNullException( "dependency" ); } foreach (var cd in ImplementedContracts.Values) { cd.Behaviors.Add( new WCFInstanceProvider<Service, TDependency>(dependency)); } } } |
内部用到了WCFInstanceProvider,意味着,我们必须提供自己的InstanceProvider,实现如下:
public class WCFInstanceProvider<Service, TDependency> : IInstanceProvider, IContractBehavior where Service : IWCFService<TDependency>, new () { private readonly TDependency _dependency; public WCFInstanceProvider(TDependency dependency) { if (dependency == null ) { throw new ArgumentNullException( "dependency" ); } _dependency = dependency; } #region IInstanceProvider Members public object GetInstance(InstanceContext instanceContext, Message message) { return GetInstance(instanceContext); } public object GetInstance(InstanceContext instanceContext) { return new Service { Dependency = _dependency }; } public void ReleaseInstance(InstanceContext instanceContext, object instance) { } #endregion #region IContractBehavior Members public void AddBindingParameters(ContractDescription contractDescription, ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, ClientRuntime clientRuntime) { } public void ApplyDispatchBehavior(ContractDescription contractDescription, ServiceEndpoint endpoint, DispatchRuntime dispatchRuntime) { dispatchRuntime.InstanceProvider = this ; } public void Validate(ContractDescription contractDescription, ServiceEndpoint endpoint) { } #endregion } |
这样,我们就差不多完成了自定义ServiceHost的定制,紧接着我们提供一个WCF服务启动关闭的基类,简化WCF服务开启和关闭的行为。
public abstract class WCFServiceBase<IChannel, Channel,TDependency> : IDisposable where Channel:IWCFService<TDependency>, new () { private readonly System.Threading.AutoResetEvent _waitor = new System.Threading.AutoResetEvent( false ); private readonly object _locker = new object (); private bool _isOpen; protected abstract string Url { get ; } protected abstract TDependency Dependency { get ; } public bool IsOpen { get { lock (_locker) { return _isOpen; } } private set { lock (_locker) { _isOpen = value; } } } public void Open() { System.Threading.ThreadPool.QueueUserWorkItem(o => { var namePipeAddress = new Uri(Url); var serverType = typeof (Channel); using (var host = new WCFServiceHost<Channel,TDependency>(Dependency,serverType, namePipeAddress)) { var serverInterfaceType = typeof (IChannel); var namePipeBiding = new NetNamedPipeBinding(); host.AddServiceEndpoint(serverInterfaceType, namePipeBiding, "" ); host.Open(); IsOpen = true ; OnOpen(); _waitor.WaitOne(); host.Close(); IsOpen = false ; } }); } public void Close() { Dispose(); } protected virtual void OnOpen() { } #region IDisposeable private bool disposed; ~WCFServiceBase() { Dispose( false ); } public void Dispose() { Dispose( true ); GC.SuppressFinalize( this ); } private void Dispose( bool disposing) { if (disposed) { return ; } if (disposing) { // 清理托管资源 } // 清理非托管资源 _waitor.Set(); disposed = true ; } #endregion IDisposeable } |
既然,提供了WCFServiceBase,我们当然应该提供一个WCFClientBase,方便WCF客户端代码的编写。
public abstract class WCFClientBase<IChannel> { protected abstract string Url { get ; } protected void Query(Action<IChannel> query, Action<Exception> error = null ) { if (query == null ) return ; System.Threading.ThreadPool.QueueUserWorkItem(o => { try { var namePipeBiding = new NetNamedPipeBinding(); var namePipeAddress = new EndpointAddress(Url); using (var client = new ChannelFactory<IChannel>(namePipeBiding, namePipeAddress)) { var updatorChannel = client.CreateChannel(); query(updatorChannel); } } catch (Exception e) { if (error != null ) error(e); } }); } protected void Query(Action<IChannel> query,Action @ finally ,Action<Exception> error= null ) { if (query == null ) return ; System.Threading.ThreadPool.QueueUserWorkItem(o => { try { var namePipeBiding= new NetNamedPipeBinding(); var namePipeAddress= new EndpointAddress(Url); using (var client= new ChannelFactory<IChannel>(namePipeBiding,namePipeAddress)){ var updatorChannel=client.CreateChannel(); query(updatorChannel); } } catch (Exception e){ if (error!= null ) error(e); } finally { if (@ finally != null ) @ finally (); } }); } protected void QuerySync(Action<IChannel> query, Action<Exception> error = null ) { if (query == null ) return ; try { var namePipeBiding = new NetNamedPipeBinding(); var namePipeAddress = new EndpointAddress(Url); using (var client = new ChannelFactory<IChannel>(namePipeBiding, namePipeAddress)) { var updatorChannel = client.CreateChannel(); query(updatorChannel); } } catch (Exception e) { if (error != null ) error(e); } } protected void QuerySync(Action<IChannel> query, Action @ finally , Action<Exception> error = null ) { if (query == null ) return ; try { var namePipeBiding = new NetNamedPipeBinding(); var namePipeAddress = new EndpointAddress(Url); using (var client = new ChannelFactory<IChannel>(namePipeBiding, namePipeAddress)) { var updatorChannel = client.CreateChannel(); query(updatorChannel); } } catch (Exception e) { if (error != null ) error(e); } finally { if (@ finally != null ) @ finally (); } } } |
以上,就是所有基础设施的构建。但是,我们的目标是用上述基础设施代码简化WCF服务和客户代码的开发。我们以提供一个WCF计算服务为例说明如何使用上述基础设施。首先是WCF接口代码:
[ServiceContract(Namespace = "LambdaClient" )] public interface ILambdaChannel { [OperationContract] int Add( int i, int j); } |
很简单,只是一个Add服务API。我们来实现服务端代码:
public class LambdaChannel:ILambdaChannel,IWCFService<LambdaProvider> { public int Add( int i, int j) { return Dependency.Add(i, j); } public LambdaProvider Dependency { get ; set ; } } public class LambdaProvider { public Func< int , int , int > Add; } public class LambdaChannelService:WCFServiceBase<ILambdaChannel,LambdaChannel,LambdaProvider> { protected override string Url { } protected override LambdaProvider Dependency { get { return new LambdaProvider{ Add = (i, j) => i + j }; } } } class Program { static void Main( string [] args) { var lambdaService = new LambdaChannelService(); lambdaService.Open(); Console.WriteLine( "Lambda计算服务已开启。" ); Console.Read(); } } |
最后,在客户端使用上述WCF计算服务:
public class LambdaChannelClient:WCFClientBase<ILambdaChannel> { protected override string Url { } public int Add( int i, int j) { int result = 0; QuerySync(channel => result=channel.Add(i, j)); return result; } } class Program { static void Main( string [] args) { var lambdaChannelClient = new LambdaChannelClient(); var result =lambdaChannelClient.Add(2, 3); Console.WriteLine( "{0}+{1}={2}" ,2,3,result); Console.Read(); } } |
实际跑一下,测试下我们的成果。
1、启动服务端。
2、启动客户端。
实验结束,测试完毕。
谢谢阅读。
标签: wcf