第六篇:单向与双向通讯

项目开发中我们时常会遇到需要异步调用的问题,有时忽略服务端的返回值,有时希望服务端在需要的时候回调,今天就来看看在WCF中如何实现。

先看不需要服务端返回值的单向调用,老规矩,直接上代码,再解释。

1、服务端

契约接口中增加一个Sleep方法:

  1. using System;
  2. using System.ServiceModel;
  3. using System.Text;
  4. namespace Server
  5. {
  6. [ServiceContract(Namespace="WCF.Demo")]
  7. public interface IData
  8. {
  9. [OperationContract]
  10. string SayHello(string userName);
  11. /// <summary>
  12. /// IsOneWay = true 表明这是一个单向调用,注意返回值是void,因为既然是单向调用,客户端肯定不会等待接收返回值的
  13. /// </summary>
  14. [OperationContract(IsOneWay = true)]
  15. void Sleep();
  16. }
  17. }

对应的实现类中,我们来实现这个方法:

  1. using System;
  2. using System.Text;
  3. namespace Server
  4. {
  5. public class DataProvider : IData
  6. {
  7. public string SayHello(string userName)
  8. {
  9. return string.Format("Hello {0}.", userName);
  10. }
  11. /// <summary>
  12. /// 实现Sleep方法,暂时不做任何事情,只是睡眠5秒
  13. /// </summary>
  14. public void Sleep()
  15. {
  16. Thread.Sleep(5000);
  17. }
  18. }
  19. }

App.config就不再列出来了,里面用的是一个netTcpBinding的endpoint。

2、客户端

首先别忘了客户端的契约要与服务端保持一致,App.config也不列出来了,里面有对应的endpoint。主要是调用的代码:

  1. using System;
  2. using System.ServiceModel;
  3. using System.ServiceModel.Channels;
  4. namespace Client
  5. {
  6. class Program
  7. {
  8. static void Main(string[] args)
  9. {
  10. var proxy = new ChannelFactory<Server.IData>("DataService").CreateChannel();
  11. //先调用SayHello方法
  12. Console.WriteLine(proxy.SayHello("WCF"));
  13. //调用一下Sleep方法,按我们的设想,它应该是异步的,所以不会阻塞后面的调用
  14. proxy.Sleep();
  15. //再调用一次SayHello方法
  16. Console.WriteLine(proxy.SayHello("WCF"));
  17. //关闭连接
  18. ((IChannel)proxy).Close();
  19. }
  20. }

按我们的设想,两次SayHello调用之间应该没有延迟,因为Sleep是异步的嘛,编译运行一下,结果……  中间卡住了5秒,这是为什么呢?

这其中涉及到一个并发模型的问题,默认情况下,WCF以单线程模型对外提供服务,也就是说,只能一个一个处理请求,即使是一个OneWay的单向调用,也只能等它处理完后才会接着处理后面的SayHello请求,所以会卡5秒。

并发模式有以下三种,MSDN上的介绍有点复杂,我给简化一下:

Single:单线程调用,请求只能一个一个处理;

Reentrant:可重入的单线程调用,本质仍是单线程,处理回调时,回调请求会进入队列尾部排队;

Multiple:多线程调用,请求是并发的响应的;

调置服务并发模型是在契约的实现类上,我们为DataService类加一个Attribute:

  1. /// <summary>
  2. /// 用ServiceBehavior为契约实现类标定行为属性,此处指定并发模型为ConcurrencyMode.Multiple,即并发访问
  3. /// </summary>
  4. [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
  5. public class DataProvider : IData
  6. {
  7. //略
  8. }

这回再编译运行一下,连续打出了2行 Hello WCF,中间不再阻塞了。

现在我们再来看看双向通讯的问题。双向通讯可以基于HTTP、TCP、Named Pipe、MSMQ,但要注意,basicHttpBinding和wsHttpBinding不行,要换用wsDualHttpBinding,它会创建两个连接来进行双向通讯。至于TCP,它天然就是双向通讯的。

1、服务端

服务契约要进行修改,增加关于回调的契约:

  1. using System;
  2. using System.ServiceModel;
  3. using System.ServiceModel.Description;
  4. namespace Server
  5. {
  6. /// <summary>
  7. /// 增加了CallbackContract的标识,用于指明针对此服务契约的回调契约是IDataCallback
  8. /// </summary>
  9. [ServiceContract(Namespace = "WCF.Demo", CallbackContract = typeof(IDataCallback))]
  10. public interface IData
  11. {
  12. [OperationContract]
  13. string SayHello(string userName);
  14. [OperationContract(IsOneWay = true)]
  15. void Sleep();
  16. }
  17. /// <summary>
  18. /// 定义服务回调契约,注意它没有契约标识,只是个一般接口
  19. /// </summary>
  20. public interface IDataCallback
  21. {
  22. /// <summary>
  23. /// 定义一个回调方法,由于回调不可能要求对方再响应,所以也标识成OneWay的调用,同样不需要有返回值
  24. /// </summary>
  25. [OperationContract(IsOneWay = true)]
  26. void SleepCallback(string text);
  27. }
  28. }

对应的契约实现类要修改一下:

  1. using System;
  2. using System.ServiceModel;
  3. using System.ServiceModel.Description;
  4. using System.Threading;
  5. using System.Net;
  6. namespace Server
  7. {
  8. [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
  9. public class DataProvider : IData
  10. {
  11. public string SayHello(string userName)
  12. {
  13. string.Format("Hello {0}.", userName);
  14. }
  15. public void Sleep()
  16. {
  17. //先睡5秒
  18. Thread.Sleep(5000);
  19. //用OperationContext.Current来获取指定类型的回调对象
  20. var callback = OperationContext.Current.GetCallbackChannel<IDataCallback>();
  21. //回调SleepCallback方法,并传递参数
  22. callback.SleepCallback("睡醒了");
  23. }
  24. }
  25. }

2、客户端

仍然提醒一下别忘了把新的服务契约更新到客户端。客户端的调用要调整一下:

  1. using System;
  2. using System.ServiceModel;
  3. using System.ServiceModel.Channels;
  4. namespace Client
  5. {
  6. class Program
  7. {
  8. static void Main(string[] args)
  9. {
  10. //定义一个实现回调接口的类实例
  11. var context = new DataCallbackImp();
  12. //创建代理的时候变了,要用DuplexChannelFactory,因为IData契约已经标识了有回调,所以必须要用支持双向通讯的ChannelFactory,传入刚才创建的回调实例
  13. var proxy = new DuplexChannelFactory<Server.IData>(context, "DataService").CreateChannel();
  14. //调用Sleep
  15. proxy.Sleep();
  16. //调用SayHello方法
  17. Console.WriteLine(proxy.SayHello("WCF"));
  18. //等待按任意键,先不要关连接
  19. Console.ReadKey();
  20. ((IChannel)proxy).Close();
  21. }
  22. /// <summary>
  23. /// 实现回调接口中的类,图省事写到这里了
  24. /// </summary>
  25. class DataCallbackImp : Server.IDataCallback
  26. {
  27. /// <summary>
  28. /// 实现SleepCallback方法
  29. /// </summary>
  30. public void SleepCallback(string text)
  31. {
  32. Console.WriteLine("收到回调了:" + text);
  33. }
  34. }
  35. }

编译运行,屏幕先显示一行“Hello WCF.”,过5秒后显示“收到回调了:睡醒了”。

转载于:https://blog.51cto.com/boytnt/803655

WCF简单教程(6) 单向与双向通讯相关推荐

  1. wcf简单教程(10) ajax调用,wcf简单教程(10) ajax调用

    wcf简单教程(10) ajax调用 [2021-02-11 16:23:59]  简介: php去除nbsp的方法:首先创建一个PHP代码示例文件:然后通过"preg_replace(&q ...

  2. WCF简单教程(5) 用IIS做Host

    第五篇:用IIS做Host 之前几篇的Demo中,我们一直在用控制台程序做Server,今天换IIS来做Host,在Web Application中添加WCF的服务. 其实在Web Applicati ...

  3. WCF简单教程(8) 安全 - Windows认证

    第八篇:WCF安全 WCF提供了非常丰富的加密机制与审核机制,以保证对外提供的服务安全可靠.本文是简单教程,所以只挑其中的一小部分来聊聊. 先来看看最简单的Windows认证. 所谓Windows认证 ...

  4. WCF简单教程(4) 数据契约

    第四篇:用数据契约传递自定义数据对象 之前的演示中,我们一直都是在用string类型做参数和返回值,实际项目中肯定会传递自定义的数据类型.与WebService不同,WCF想传递自定义数据,必须要将其 ...

  5. 我的WCF之旅 (11): 再谈WCF的双向通讯-基于Http的双向通讯 V.S. 基于TCP的双向通讯...

    在一个基于面向服务的分布式环境中,借助一个标准的.平台无关的Communication Infrastructure,各个Service通过SOAP Message实现相互之间的交互.这个交互的过程实 ...

  6. 地址总线是单向还是双向_粪便自动化检验技术(三)多项目联检及双向通讯技术...

    现今信息技术和网络技术越来越发达,临床实验室信息系统从无到有,从简单到复杂,特别是医院信息系统HIS和临床实验室信息系统LIS的逐渐普及并大规模使用,使得医院临床实验室的工作更加自动化.信息化.在不断 ...

  7. [经验教程]支付宝好友被删除了怎么知道及支付宝好友删除是单向还是双向?

    支付宝好友删除是单向还是双向? 支付宝好友删除是属于双向删除关系,单向删除好友列表:即支付宝好友删除后对方无法向您发送消息,但是已添加的支付宝好友还会显示在对方的好友列表中.单向删除好友是指自己删除好 ...

  8. C++的MFC 与 HTML 双向通讯

    C++中嵌入ie浏览器总结(1) - ie边框 及上下文菜单 最近项目中用html 来做界面,也就折腾了一下在wxwidget中嵌入浏览器的若干细节工作,mfc也基本是类似的,由于wxwidget中已 ...

  9. USART HMI智能串口屏与单片机双向通讯

    目录 ·HMI串口屏介绍 ·HMI串口屏开发实操 ·准备 ·界面认识 ·写命令 ·下载 ·HMI串口屏与单片机(stm32)双向通信 [ 功能实现: STM32控制串口屏对应的数值.文本完成相应变化 ...

最新文章

  1. 2018/8/26 PSO-based Clustering Techniques to Solve Multimodal Optimization Problems: A Survey
  2. 设计模式之迭代器模式java实现代码
  3. 64位CentOs7源码安装mysql-5.6.35过程分享
  4. [MySQL优化案例]系列 -- OPTIMIZE的威力
  5. Redis简单案例(二) 网站最近的访问用户
  6. 深入SQL SERVER 2000的内存管理机制
  7. 剑指offer-面试题13.在O(1)时间删除链表节点
  8. arcgis投影数据计算度分秒
  9. wxpython实现简单图书管理系统
  10. VMware虚拟网络设置(NAT模式,桥接模式,仅主机模式设置),再也不用担心虚拟机连不上网了。
  11. php网上商城拟解决的问题是,上次说的软件商城BUG,已找到问题,并解决~
  12. 初识Jasima-Jasima中的建模对象
  13. C# DateTime的ToString()方法的使用
  14. Android 自定义控件之---3D画廊
  15. win8系统用友U8服务器的设置,用友u8服务器参数配置
  16. 云安全类型及预防方法
  17. CentOS上使用docker安装redis
  18. Android 点击生成二维码
  19. java基础入门传智播客电子版,手撕面试官
  20. java全栈系列之JavaSE--递归详解022

热门文章

  1. PaperNotes(6)-GAN/DCGAN/WGAN/WGAN-GP/WGAN-SN-网络结构/实验效果
  2. 代码重构 防火墙 相关知识
  3. Python学习5 元组基础知识和常用函数
  4. Android MotionEvent中getX()、getRawX()和getTop()的区别
  5. IDR、CRA、BLA、RASL、RADL、closed-gop、open-gop
  6. Eclipse GCC 入门
  7. android studio : clang++.exe: error: invalid linker name in argument '-fuse-ld=bfd
  8. 深入理解 PHP7 中全新的 zval 容器和引用计数机制
  9. LeetCode--171--Excel表列序号
  10. webpack自动化构建脚本指令npm run dev/build