Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4111356
  • 博文数量: 855
  • 博客积分: 17977
  • 博客等级: 上将
  • 技术积分: 8236
  • 用 户 组: 普通用户
  • 注册时间: 2005-08-26 09:59
  • 认证徽章:
个人简介

一个好老好老的老程序员了。

文章分类

全部博文(855)

文章存档

2019年(12)

2018年(88)

2017年(130)

2015年(5)

2014年(12)

2013年(41)

2012年(36)

2011年(272)

2010年(1)

2009年(53)

2008年(65)

2007年(47)

2006年(81)

2005年(12)

分类: C#/.net

2018-07-25 09:10:43

在WCF通信中,如果实现要得到服务端处理的结果,一种方式是在契约中指定调用方法带返回值(IsOneWay=false),但这种方式是有缺陷的,如果服务端处理时间过长,则客户端也需要长时间等待。
另一种方式是通过双工通信,使用回调来实现。但回调的时候,回调方法中不应该有耗时操作,否则当服务端处理完成退出的时间,回调消息会丢失。
目前WCF支持双工的绑定方式有:WSDualHttpBinding,NetTcpBinding与NetNamedPipeBinding三种,其它绑定方式不支持双工。
下面以一个简短的例子说明双工通信。
1、定义契约

点击(此处)折叠或打开

  1. [ServiceContract(Namespace = "http://cnblog.com/zhili/", CallbackContract = typeof(ICallback))]
  2. public interface ICalculator
  3. {
  4.     [OperationContract(IsOneWay = true)]
  5.     void Multiple(double a, double b);
  6.     [OperationContract(IsOneWay = true)]
  7.     void DisplayString(string name);
  8. }


其中指定了回调契约是ICallback。

点击(此处)折叠或打开

  1. // 回调契约的定义,此时回调契约不需要应用ServiceContractAttribute特性
  2. public interface ICallback
  3. {
  4.     [OperationContract(IsOneWay = true)]
  5.     void DisplayResult(double x, double y, double result);

  6.     [OperationContract(IsOneWay = false, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
  7.     string DisplayStringResult(string retStr);
  8. }


我们看到,回调第二个方法有返回值。这个在服务行为配置中要有特殊配置,否则会卡死。
2、服务端实现
实现服务契约:

点击(此处)折叠或打开

  1. // 服务契约的实现
  2. [ServiceBehavior(IncludeExceptionDetailInFaults = true,ConcurrencyMode = ConcurrencyMode.Multiple)]
  3. public class CalculatorService : ICalculator
  4. {
  5.     #region ICalculator Members

  6.     public void Multiple(double a, double b)
  7.     {
  8.         for (int i = 1; i < 100; i++)
  9.         {
  10.             double result = a * b;

  11.             // 通过客户端实例通道
  12.             ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();

  13.             // 对客户端操作进行回调
  14.             callback.DisplayResult(a, b, result);
  15.             Console.WriteLine("Callback Times {0} at time {1}", i, DateTime.Now.ToString("hh:mm:ss tt zz"));
  16.         }
  17.         Program.ExitFlag = true;
  18.     }

  19.     public void DisplayString(string name)
  20.     {
  21.          
  22.         for (int i = 1; i < 100; i++)
  23.         {
  24.             // 通过客户端实例通道
  25.             ICallback callback = OperationContext.Current.GetCallbackChannel<ICallback>();
  26.                
  27.             // 对客户端操作进行回调
  28.             string retStr = callback.DisplayStringResult("Hello " + name);
  29.             Console.WriteLine("Callback Times {0} at time {1}, ret={2}", i, DateTime.Now.ToString("hh:mm:ss tt zz"), retStr);
  30.         }
  31.         Program.ExitFlag = true;
  32.     }

  33.     #endregion
  34. }


其中ServiceBehavior属性的ConcurrencyMode = ConcurrencyMode.Multiple配置就是配置回调方法带返回值问题(IsOneWay=false),如果不设置这个属性,或者设置为Single,上述回调方法调用时会卡死。
主程序如下:

点击(此处)折叠或打开

  1. class Program
  2. {
  3.     public static bool ExitFlag = false;
  4.     static void Main(string[] args)
  5.     {
  6.         using (ServiceHost host = new ServiceHost(typeof(CalculatorService)))
  7.         {
  8.             host.Opened += delegate
  9.             {
  10.                 Console.WriteLine("Service start now....");
  11.             };

  12.             host.Open();
  13.             while (!ExitFlag)
  14.             {
  15.                 Thread.Sleep(500);
  16.             }
  17.         }
  18.     }
  19. }


主程序配置(App.Config):

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3.     <system.serviceModel>
  4.         <behaviors>
  5.             <serviceBehaviors>
  6.                 <behavior>
  7.                     <serviceMetadata httpGetEnabled="true" httpGetUrl="http://localhost:8080/Metadata"/>
  8.                 </behavior>
  9.             </serviceBehaviors>
  10.         </behaviors>
  11.         <services>
  12.             <service name="NMS.WCFDemo.Server.CalculatorService">
  13.                 <endpoint address="net.tcp://localhost:9003/CalculatorService" binding="netTcpBinding" contract="NMS.WCFDemo.Contract.ICalculator"/>
  14.             </service>
  15.         </services>
  16.     </system.serviceModel>
  17. </configuration>


3、客户端
创建完客户端程序后,添加一个服务引用,指向上面配置文件的地址http://localhost:8080/Metadata获取服务引用。(添加服务引用时服务程序必须已经在运行)
实现回调契约:

点击(此处)折叠或打开

  1. // 客户端中对回调契约的实现
  2. public class CallbackWCFService : ICalculatorCallback
  3. {
  4.     private int i = 1;
  5.     public void DisplayResult(double a, double b, double result)
  6.     {
  7.         Console.WriteLine("{4} : {0} * {1} = {2} ====== AT Time {3}", a, b, result, DateTime.Now.ToString("hh:mm:ss tt zz"), i++);
  8.         Thread.Sleep(1000);
  9.     }

  10.     public string DisplayStringResult(string retStr)
  11.     {
  12.         Console.WriteLine("{0} : recevie msg {1} ====== AT Time {2}", i++, retStr, DateTime.Now.ToString("hh:mm:ss tt zz"));
  13.         Thread.Sleep(1000);
  14.         return i.ToString();
  15.     }
  16. }


客户端主程序:

点击(此处)折叠或打开

  1. // 客户端实现,测试回调操作
  2. class Program
  3. {
  4.     static void Main(string[] args)
  5.     {
  6.         InstanceContext instanceContex = new InstanceContext(new CallbackWCFService());
  7.         CalculatorClient proxy = new CalculatorClient(instanceContex);
  8.         if (args[0] == "1")
  9.         {
  10.             proxy.Multiple(2, 3);
  11.         }
  12.         else
  13.         {
  14.             Console.WriteLine("Call string ...");
  15.             proxy.DisplayString("Client");
  16.         }
  17.         Console.Read();
  18.     }
  19. }


客户端配置文件(App.Config)

点击(此处)折叠或打开

  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <configuration>
  3.     <startup>
  4.         <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
  5.     </startup>
  6.     <system.serviceModel>
  7.         <bindings>
  8.             <netTcpBinding>
  9.                 <binding name="NetTcpBinding_ICalculator" />
  10.                 <binding name="NetTcpBinding_ICalculator1" />
  11.             </netTcpBinding>
  12.         </bindings>
  13.         <client>
  14.             <endpoint address="net.tcp://localhost:9003/CalculatorService"
  15.                 binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICalculator"
  16.                 contract="NMS.WCFDemo.Contract.ICalculator" name="NetTcpBinding_ICalculator" />
  17.             <endpoint address="net.tcp://localhost:9003/CalculatorService"
  18.                 binding="netTcpBinding" bindingConfiguration="NetTcpBinding_ICalculator1"
  19.                 contract="ServiceReference1.ICalculator" name="NetTcpBinding_ICalculator1">
  20.                 <identity>
  21.                     <userPrincipalName value="DESKTOP-4D9M16H\wangcc" />
  22.                 </identity>
  23.             </endpoint>
  24.         </client>
  25.     </system.serviceModel>
  26. </configuration>


然后运行程序就能看到效果了。

阅读(2703) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~
评论热议
请登录后评论。

登录 注册