WCF服务属性注入基础设施

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
     {
         get  { return  @"net.pipe://localhost/lambda" ; }
     }
 
     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
     {
         get  { return  @"net.pipe://localhost/lambda" ; }
     }
 
     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

你可能感兴趣的:(WCF)