WCF透明代理类,动态调用,支持async/await

来源:互联网 发布:村上作品推荐 知乎 编辑:程序博客网 时间:2024/05/22 15:14

原文地址:http://www.cnblogs.com/felixnet/p/wcf_client_transparent_proxy_channelfactory.html

我们希望WCF客户端调用采用透明代理方式,不用添加服务引用,也不用Invoke的方式,通过ChannelFactory<>动态产生通道,实现服务接口进行调用,并且支持async/await,当然也不用在Config中配置serviceModel。

服务端代码:

复制代码
[ServiceContract]public interface IGameService{    [OperationContract]    Task DoWorkAsync(string arg);    [OperationContract]    void DoWork(string arg);}public class GameService : IGameService{    public async Task<string> DoWorkAsync(string arg)    {        return await Task.FromResult($"Hello {arg}, I am the GameService.");    }    public string DoWork(string arg)    {        return $"Hello {arg}, I am the GameService.";    }}[ServiceContract]public interface IPlayerService{    [OperationContract]    Task<string> DoWorkAsync(string arg);    [OperationContract]    string DoWork(string arg);}public class PlayerService : IPlayerService{    public async Task<string> DoWorkAsync(string arg)    {        return await Task.FromResult($"Hello {arg}, I am the PlayerService.");    }    public async string DoWork(string arg)    {        return $"Hello {arg}, I am the PlayerService.";    }}
复制代码

 

代理类

动态创建服务对象,ChannelFactory<T>的运用,一个抽象类

复制代码
namespace Wettery.Infrastructure.Wcf{    public enum WcfBindingType    {        BasicHttpBinding,        NetNamedPipeBinding,        NetPeerTcpBinding,        NetTcpBinding,        WebHttpBinding,        WSDualHttpBinding,        WSFederationHttpBinding,        WSHttpBinding    }    public abstract class WcfChannelClient<TChannel> : IDisposable    {        public abstract string ServiceUrl { get; }        private Binding _binding;        public virtual Binding Binding        {            get            {                if (_binding == null)                    _binding = CreateBinding(WcfBindingType.NetTcpBinding);                return _binding;            }        }        protected TChannel _channel;        public TChannel Channel        {            get { return _channel; }        }        protected IClientChannel ClientChannel        {            get { return (IClientChannel)_channel; }        }        public WcfChannelClient()        {            if (string.IsNullOrEmpty(this.ServiceUrl)) throw new NotSupportedException("ServiceUrl is not overridden by derived classes.");            var chanFactory = new ChannelFactory<TChannel>(this.Binding, this.ServiceUrl);            _channel = chanFactory.CreateChannel();            this.ClientChannel.Open();        }        protected virtual void Dispose(bool disposing)        {            if (disposing && this.ClientChannel != null)            {                try                {                    this.ClientChannel.Close(TimeSpan.FromSeconds(2));                }                catch                {                    this.ClientChannel.Abort();                }            }            //TODO: free unmanaged resources        }        public void Dispose()        {            Dispose(true);            GC.SuppressFinalize(this);        }        ~WcfChannelClient()        {            Dispose(false);        }        private static Binding CreateBinding(WcfBindingType binding)        {            Binding bindinginstance = null;            if (binding == WcfBindingType.BasicHttpBinding)            {                BasicHttpBinding ws = new BasicHttpBinding();                ws.MaxBufferSize = 2147483647;                ws.MaxBufferPoolSize = 2147483647;                ws.MaxReceivedMessageSize = 2147483647;                ws.ReaderQuotas.MaxStringContentLength = 2147483647;                ws.CloseTimeout = new TimeSpan(0, 10, 0);                ws.OpenTimeout = new TimeSpan(0, 10, 0);                ws.ReceiveTimeout = new TimeSpan(0, 10, 0);                ws.SendTimeout = new TimeSpan(0, 10, 0);                bindinginstance = ws;            }            else if (binding == WcfBindingType.NetNamedPipeBinding)            {                NetNamedPipeBinding ws = new NetNamedPipeBinding();                ws.MaxReceivedMessageSize = 65535000;                bindinginstance = ws;            }            else if (binding == WcfBindingType.NetPeerTcpBinding)            {                //NetPeerTcpBinding ws = new NetPeerTcpBinding();                //ws.MaxReceivedMessageSize = 65535000;                //bindinginstance = ws;                throw new NotImplementedException();            }            else if (binding == WcfBindingType.NetTcpBinding)            {                NetTcpBinding ws = new NetTcpBinding();                ws.MaxReceivedMessageSize = 65535000;                ws.Security.Mode = SecurityMode.None;                bindinginstance = ws;            }            else if (binding == WcfBindingType.WebHttpBinding)            {                WebHttpBinding ws = new WebHttpBinding(); //Restful style                ws.MaxReceivedMessageSize = 65535000;                bindinginstance = ws;            }            else if (binding == WcfBindingType.WSDualHttpBinding)            {                WSDualHttpBinding ws = new WSDualHttpBinding();                ws.MaxReceivedMessageSize = 65535000;                bindinginstance = ws;            }            else if (binding == WcfBindingType.WSFederationHttpBinding)            {                WSFederationHttpBinding ws = new WSFederationHttpBinding();                ws.MaxReceivedMessageSize = 65535000;                bindinginstance = ws;            }            else if (binding == WcfBindingType.WSHttpBinding)            {                WSHttpBinding ws = new WSHttpBinding(SecurityMode.None);                ws.MaxReceivedMessageSize = 65535000;                ws.Security.Message.ClientCredentialType = MessageCredentialType.Windows;                ws.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;                bindinginstance = ws;            }            return bindinginstance;        }            }}
复制代码

针对每个WCF服务派生一个代理类,在其中重写ServiceUrl与Binding,ServiceUrl可以配置到Config中,Binding不重写默认采用NetTcpBinding

复制代码
public class GameServiceClient : WcfChannelClient<IGameService>    {        public override string ServiceUrl        {            get            {                return "net.tcp://localhost:21336/GameService.svc";            }        }    }public class PlayerServiceClient : WcfChannelClient<IPlayerService>    {        public override string ServiceUrl        {            get            {                return "net.tcp://localhost:21336/PlayerService.svc";            }        }    }
复制代码

客户端调用

复制代码
using (var client = new GameServiceClient()){    client.Channel.DoWork("thinkpig");  //无返回值    await client.Channel.DoWorkAsync("thinkpig");  //无返回值异步}using (var client = new PlayerServiceClient()){    var result = client.Channel.DoWork("thinkdog");  //有返回值    result = await client.Channel.DoWorkAsync("thinkdog");  //有返回值异步}
复制代码

 

关于WCF寄宿主机可以参考前两篇文章

WCF绑定netTcpBinding寄宿到控制台应用程序

WCF绑定netTcpBinding寄宿到IIS