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
浙公网安备 33010602011771号