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