我們希望WCF客戶端調用採用透明代理方式,不用添加服務引用,也不用Invoke的方式,通過ChannelFactory<>動態產生通道,實現服務介面進行調用,並且支持async/await,當然也不用在Config中配置serviceModel。 服務端代碼: 代理類 動態創建服務對象,Channe ...
我們希望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; } } }View Code
針對每個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寄宿主機可以參考前兩篇文章