WCF透明代理類,動態調用,支持async/await


我們希望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寄宿主機可以參考前兩篇文章

WCF綁定netTcpBinding寄宿到控制台應用程序

WCF綁定netTcpBinding寄宿到IIS


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM