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

时间:2021-07-24 11:12:08

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

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

服务端代码:

WCF透明代理类,动态调用,支持async/await
[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.";
}
}
WCF透明代理类,动态调用,支持async/await

 

代理类

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

WCF透明代理类,动态调用,支持async/awaitWCF透明代理类,动态调用,支持async/await
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透明代理类,动态调用,支持async/await

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

WCF透明代理类,动态调用,支持async/await
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";
}
}
}
WCF透明代理类,动态调用,支持async/await

客户端调用

WCF透明代理类,动态调用,支持async/await
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透明代理类,动态调用,支持async/await

 

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

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

WCF绑定netTcpBinding寄宿到IIS