zoukankan      html  css  js  c++  java
  • 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
  • 相关阅读:
    [Flash开发笔记] ActionScript 生成伪 Guid
    [Flash开发笔记] 如何在as2.0中使用自定义类事件
    vs2005 智能感知不正常的解决办法
    [Flash开发笔记] 自定义ActionScript中的trim函数,取回车函数,字节换算函数
    爱你不容易——ExternalInterface
    软件测试中开发团队和测试团队的职责
    [Flash开发笔记] 正确理解MovieClipLoader的onLoadComplete事件
    ActionScript 中的字符串替换函数
    “hello world”PHP
    使用"类型文件"(typed File),创建自己的"数据库"
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3186488.html
Copyright © 2011-2022 走看看