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

服务端代码:

  1. [ServiceContract]
  2. public interface IGameService
  3. {
  4. [OperationContract]
  5. Task DoWorkAsync(string arg);
  6.  
  7. [OperationContract]
  8. void DoWork(string arg);
  9. }
  10.  
  11. public class GameService : IGameService
  12. {
  13. public async Task<string> DoWorkAsync(string arg)
  14. {
  15. return await Task.FromResult($"Hello {arg}, I am the GameService.");
  16. }
  17. public string DoWork(string arg)
  18. {
  19. return $"Hello {arg}, I am the GameService.";
  20. }
  21. }
  22.  
  23. [ServiceContract]
  24. public interface IPlayerService
  25. {
  26. [OperationContract]
  27. Task<string> DoWorkAsync(string arg);
  28.  
  29. [OperationContract]
  30. string DoWork(string arg);
  31. }
  32.  
  33. public class PlayerService : IPlayerService
  34. {
  35. public async Task<string> DoWorkAsync(string arg)
  36. {
  37. return await Task.FromResult($"Hello {arg}, I am the PlayerService.");
  38. }
  39. public async string DoWork(string arg)
  40. {
  41. return $"Hello {arg}, I am the PlayerService.";
  42. }
  43. }

代理类

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

  1. namespace Wettery.Infrastructure.Wcf
  2. {
  3. public enum WcfBindingType
  4. {
  5. BasicHttpBinding,
  6. NetNamedPipeBinding,
  7. NetPeerTcpBinding,
  8. NetTcpBinding,
  9. WebHttpBinding,
  10. WSDualHttpBinding,
  11. WSFederationHttpBinding,
  12. WSHttpBinding
  13. }
  14.  
  15. public abstract class WcfChannelClient<TChannel> : IDisposable
  16. {
  17. public abstract string ServiceUrl { get; }
  18.  
  19. private Binding _binding;
  20. public virtual Binding Binding
  21. {
  22. get
  23. {
  24. if (_binding == null)
  25. _binding = CreateBinding(WcfBindingType.NetTcpBinding);
  26.  
  27. return _binding;
  28. }
  29. }
  30.  
  31. protected TChannel _channel;
  32. public TChannel Channel
  33. {
  34. get { return _channel; }
  35. }
  36. protected IClientChannel ClientChannel
  37. {
  38. get { return (IClientChannel)_channel; }
  39. }
  40.  
  41. public WcfChannelClient()
  42. {
  43. if (string.IsNullOrEmpty(this.ServiceUrl)) throw new NotSupportedException("ServiceUrl is not overridden by derived classes.");
  44. var chanFactory = new ChannelFactory<TChannel>(this.Binding, this.ServiceUrl);
  45. _channel = chanFactory.CreateChannel();
  46. this.ClientChannel.Open();
  47. }
  48.  
  49. protected virtual void Dispose(bool disposing)
  50. {
  51. if (disposing && this.ClientChannel != null)
  52. {
  53. try
  54. {
  55. this.ClientChannel.Close(TimeSpan.FromSeconds());
  56. }
  57. catch
  58. {
  59. this.ClientChannel.Abort();
  60. }
  61. }
  62.  
  63. //TODO: free unmanaged resources
  64. }
  65. public void Dispose()
  66. {
  67. Dispose(true);
  68. GC.SuppressFinalize(this);
  69. }
  70. ~WcfChannelClient()
  71. {
  72. Dispose(false);
  73. }
  74.  
  75. private static Binding CreateBinding(WcfBindingType binding)
  76. {
  77. Binding bindinginstance = null;
  78. if (binding == WcfBindingType.BasicHttpBinding)
  79. {
  80. BasicHttpBinding ws = new BasicHttpBinding();
  81. ws.MaxBufferSize = ;
  82. ws.MaxBufferPoolSize = ;
  83. ws.MaxReceivedMessageSize = ;
  84. ws.ReaderQuotas.MaxStringContentLength = ;
  85. ws.CloseTimeout = new TimeSpan(, , );
  86. ws.OpenTimeout = new TimeSpan(, , );
  87. ws.ReceiveTimeout = new TimeSpan(, , );
  88. ws.SendTimeout = new TimeSpan(, , );
  89. bindinginstance = ws;
  90. }
  91. else if (binding == WcfBindingType.NetNamedPipeBinding)
  92. {
  93. NetNamedPipeBinding ws = new NetNamedPipeBinding();
  94. ws.MaxReceivedMessageSize = ;
  95. bindinginstance = ws;
  96. }
  97. else if (binding == WcfBindingType.NetPeerTcpBinding)
  98. {
  99. //NetPeerTcpBinding ws = new NetPeerTcpBinding();
  100. //ws.MaxReceivedMessageSize = 65535000;
  101. //bindinginstance = ws;
  102. throw new NotImplementedException();
  103. }
  104. else if (binding == WcfBindingType.NetTcpBinding)
  105. {
  106. NetTcpBinding ws = new NetTcpBinding();
  107. ws.MaxReceivedMessageSize = ;
  108. ws.Security.Mode = SecurityMode.None;
  109. bindinginstance = ws;
  110. }
  111. else if (binding == WcfBindingType.WebHttpBinding)
  112. {
  113. WebHttpBinding ws = new WebHttpBinding(); //Restful style
  114. ws.MaxReceivedMessageSize = ;
  115. bindinginstance = ws;
  116. }
  117. else if (binding == WcfBindingType.WSDualHttpBinding)
  118. {
  119. WSDualHttpBinding ws = new WSDualHttpBinding();
  120. ws.MaxReceivedMessageSize = ;
  121. bindinginstance = ws;
  122. }
  123. else if (binding == WcfBindingType.WSFederationHttpBinding)
  124. {
  125. WSFederationHttpBinding ws = new WSFederationHttpBinding();
  126. ws.MaxReceivedMessageSize = ;
  127. bindinginstance = ws;
  128. }
  129. else if (binding == WcfBindingType.WSHttpBinding)
  130. {
  131. WSHttpBinding ws = new WSHttpBinding(SecurityMode.None);
  132. ws.MaxReceivedMessageSize = ;
  133. ws.Security.Message.ClientCredentialType = MessageCredentialType.Windows;
  134. ws.Security.Transport.ClientCredentialType = HttpClientCredentialType.Windows;
  135. bindinginstance = ws;
  136. }
  137. return bindinginstance;
  138.  
  139. }
  140. }
  141. }

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

  1. public class GameServiceClient : WcfChannelClient<IGameService>
  2. {
  3. public override string ServiceUrl
  4. {
  5. get
  6. {
  7. return "net.tcp://localhost:21336/GameService.svc";
  8. }
  9. }
  10. }
  11.  
  12. public class PlayerServiceClient : WcfChannelClient<IPlayerService>
  13. {
  14. public override string ServiceUrl
  15. {
  16. get
  17. {
  18. return "net.tcp://localhost:21336/PlayerService.svc";
  19. }
  20. }
  21. }

客户端调用

  1. using (var client = new GameServiceClient())
  2. {
  3. client.Channel.DoWork("thinkpig"); //无返回值
  4. await client.Channel.DoWorkAsync("thinkpig"); //无返回值异步
  5. }
  6.  
  7. using (var client = new PlayerServiceClient())
  8. {
  9. var result = client.Channel.DoWork("thinkdog"); //有返回值
  10. result = await client.Channel.DoWorkAsync("thinkdog"); //有返回值异步
  11. }

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

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

WCF绑定netTcpBinding寄宿到IIS

WCF透明代理类,动态调用,支持async/await的更多相关文章

  1. WCF 透明代理

    现在我们通过类似的原理创建一个用于模拟WCF服务端和客户端工作原理的模拟程序.[源代码从这里下载] 目录 一.基本的组件和执行流程 二.创建自定义HttpHandler实现对服务调用请求的处理 三.定 ...

  2. 终于解决:升级至.NET 4.6.1后VS2015生成WCF客户端代理类的问题

    在Visual Studio 2015中将一个包含WCF引用的项目的targetFramework从4.5改为4.6.1的时候,VS2015会重新生成WCF客户端代理类.如果WCF引用配置中选中了&q ...

  3. Node 7.6默认支持Async/Await

    Node.js 7.6正式默认支持async/await功能,并能够使低内存设备获得更出色的性能. Node 7.6对async/await的支持来自于将V8(Chromium JavaScript引 ...

  4. WCF服务代理类-学习

    类:ServiceDescriptionImporter Class 公开一种为 XML Web services 生成客户端代理类的方法. 地址:https://docs.microsoft.com ...

  5. 为什么 array.foreach 不支持 async/await

    一.背景 react 项目中,渲染组件时,显示的数据一直有问题,本来以为是 react 组件的问题,后来才发现罪魁祸首在 fetch 数据的过程,因为我用了 async/await ,而却搭配了 fo ...

  6. 动态得到WCF的代理类并生成代码

    Uri uri = new Uri("http://localhost:6580/Service1.svc?wsdl");             MetadataExchange ...

  7. C# 通过反射类动态调用DLL方法

    网上看了很多关于反射的思路和方法,发现这个还算不错 //使用反射方: using System; using System.Collections.Generic; using System.Linq ...

  8. 关于IIS寄宿WCF服务,客户端不能生成代理类

    我在使用VS2010写好WCF的Web服务后,部署在IIS7.0上,可以在IE9上进行访问,并且能显示XML数据,如下图 然后我在项目的客户端进行服务的添加引用,如下图 VS2010自动生成代理类,但 ...

  9. 创建一个简单的WCF程序2——手动开启/关闭WCF服务与动态调用WCF地址

    一.创建WCF服务器 1.创建WCF服务器的窗体应用程序 打开VS2010,选择文件→新建→项目菜单项,在打开的新建项目对话框中,依次选择Visual C#→Windows→Windows窗体应用程序 ...

随机推荐

  1. Android Studio模拟器磁盘空间不足(Not enough disk space to run AVD)

    在Android Studio中运行模拟器时,提示Error: Not enough disk space to run AVD '....'. Exiting.是说安装模拟的磁盘空间不足,导致无法运 ...

  2. BM递推

    从别的大佬处看到的模板 #include<bits/stdc++.h> #define fi first #define se second #define INF 0x3f3f3f3f ...

  3. MYSQL分组合并函数

    MySQL中group_concat函数完整的语法如下:group_concat([DISTINCT] 要连接的字段 [Order BY ASC/DESC 排序字段] [Separator '分隔符' ...

  4. Quartz使用

    背景 很多时候,项目需要在不同时刻,执行一个或很多个不同的作业. Windows执行计划这时并不能很好的满足需求了,迫切需要一个更为强大,方便管理,集群部署的作业调度框架. 介绍 Quartz一个开源 ...

  5. Django REST framework的分页

    DRF分页组件 为什么要使用分页 我们数据表中可能会有成千上万条数据,当我们访问某张表的所有数据时,我们不太可能需要一次把所有的数据都展示出来,因为数据量很大,对服务端的内存压力比较大还有就是网络传输 ...

  6. python argparse(参数解析)模块学习(一)

    class ArgumentParser(_AttributeHolder, _ActionsContainer): """Object for parsing comm ...

  7. 数组中的逆序对(python)

    题目描述 在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对.输入一个数组,求出这个数组中的逆序对的总数P.并将P对1000000007取模的结果输出. 即输出P%1000 ...

  8. MongoDB入门(一)

    文档 文档是MongoDB中的基本数据结构,型如:{"name":"Jack","lastname":"xi"} 键值对 ...

  9. 65. Valid Number 判断字符串是不是数字

    [抄题]: Validate if a given string is numeric. Some examples:"0" => true" 0.1 " ...

  10. Admin注册和路由分发详解

    Admin注册和路由分发详解 1.启动 #autodiscover_modules('admin', register_to=site) 2.注册 1.单例对象 admin.site = AdminS ...