WCF之消息模式分为:
1、请求/答复模式
2、单向模式
3、双工模式

其中,请求/答复模式,在博文:

WCF 入门教程一(动手新建第一个WCF程序并部署)

WCF 入门教程二

中进行了详细介绍,此处将主要介绍:单向模式与双工模式。

1、首先,先创建一个WCF应用程序:

创建完成后,目录如下:

2、删除IService1.cs和Serivce1.svc,或者修改名称为:CalculateService.svc与ICalculateService.cs后,显示如下:

3、ICalculateService.cs文件内容如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.Serialization;
  5. using System.ServiceModel;
  6. using System.ServiceModel.Web;
  7. using System.Text;
  8. namespace WcfDuplexTest
  9. {
  10. // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的接口名“IService”。
  11. [ServiceContract(Namespace = "http://blog.csdn.net/jiankunking",
  12. SessionMode = SessionMode.Required, CallbackContract = typeof(ICalculatorDuplexCallback))]
  13. public interface ICalculateService
  14. {
  15. [OperationContract(IsOneWay = true)]
  16. void GetData(string value);
  17. [OperationContract]
  18. CompositeType Clear();
  19. // TODO: 在此添加您的服务操作
  20. }
  21. /*我们可以看到它有一个ICalculatorDuplexCallback的接口,由于它在ServiceContract中被标记为CallbackContract = typeof(ICalculatorDuplexCallback),所以它用于客户端回调。
  22. * 意即,服务端可以通过此接口中的方法将数据发送给客户端,客户端只需要实现此接口,即可接收到服务端发送过来的消息。*/
  23. public interface ICalculatorDuplexCallback
  24. {
  25. [OperationContract(IsOneWay = true)]
  26. void ComplexCalculate(string result);
  27. [OperationContract]
  28. string GetComplexCalculateResult(string value);
  29. }
  30. // 使用下面示例中说明的数据协定将复合类型添加到服务操作
  31. [DataContract]
  32. public class CompositeType
  33. {
  34. bool boolValue = true;
  35. string stringValue = "Hello ";
  36. [DataMember]
  37. public bool BoolValue
  38. {
  39. get { return boolValue; }
  40. set { boolValue = value; }
  41. }
  42. [DataMember]
  43. public string StringValue
  44. {
  45. get { return stringValue; }
  46. set { stringValue = value; }
  47. }
  48. }
  49. }

4、CalculateService.svc文件中的内容:

  1. <pre name="code" class="csharp">using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Runtime.Serialization;
  5. using System.ServiceModel;
  6. using System.ServiceModel.Web;
  7. using System.Text;
  8. namespace WcfDuplexTest
  9. {
  10. /*ServiceContract的SessionMode
  11. 用于Contract上的枚举, 3种:
  12. Allowed: 指定协定永支持会话
  13. Required:指定协定必须会话绑定,否则将引发异常。BasicHttpBinding不支持会话,所以当使用BasicHttpBinding的时候毕会异常;
  14. NotAllowed:指定协定永不支持启动会话的绑定。*/
  15. // 注意: 使用“重构”菜单上的“重命名”命令,可以同时更改代码和配置文件中的类名“Service”。
  16. [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]
  17. public class CalculateService : ICalculateService
  18. {
  19. //声明一个ICalculatorDuplexCallback接口的对象
  20. ICalculatorDuplexCallback callback = null;
  21. //CalculateService类的构造方法
  22. public CalculateService()
  23. {
  24. //实例化一个ICalculatorDuplexCallback
  25. callback = OperationContext.Current.GetCallbackChannel<ICalculatorDuplexCallback>();
  26. }
  27. public void GetData(string value)
  28. {
  29. //服务端调用客户端的ComplexCalculate方法
  30. callback.ComplexCalculate(value);
  31. }
  32. public CompositeType Clear()
  33. {
  34. CompositeType composite = new CompositeType();
  35. composite.BoolValue = false;
  36. //服务端调用客户端的GetComplexCalculateResult方法
  37. composite.StringValue = "测试回调客户端带有返回值的方法\r\n " + callback.GetComplexCalculateResult("客户端方法:GetComplexCalculateResult");
  38. return composite;
  39. }
  40. }
  41. }</pre>

5、修改Web.config的配置文件

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <configuration>
  3. <system.web>
  4. <compilation debug="true" targetFramework="4.0" />
  5. </system.web>
  6. <system.serviceModel>
  7. <!--WCF应用程序 一下services节点需要自己手动添加-->
  8. <services>
  9. <service name="WcfDuplexTest.CalculateService">
  10. <endpoint address="" binding="wsDualHttpBinding" contract="WcfDuplexTest.ICalculateService">
  11. <identity>
  12. <dns value="localhost" />
  13. </identity>
  14. </endpoint>
  15. <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
  16. <host>
  17. <baseAddresses>
  18. <add baseAddress="http://localhost:8732/Design_Time_Addresses/WcfDuplexTest/CalculateService/" />
  19. </baseAddresses>
  20. </host>
  21. </service>
  22. </services>
  23. <behaviors>
  24. <serviceBehaviors>
  25. <behavior>
  26. <!-- 为避免泄漏元数据信息,请在部署前将以下值设置为 false 并删除上面的元数据终结点 -->
  27. <serviceMetadata httpGetEnabled="true"/>
  28. <!-- 要接收故障异常详细信息以进行调试,请将以下值设置为 true。在部署前设置为 false 以避免泄漏异常信息 -->
  29. <serviceDebug includeExceptionDetailInFaults="true"/>
  30. </behavior>
  31. </serviceBehaviors>
  32. </behaviors>
  33. <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  34. </system.serviceModel>
  35. <system.webServer>
  36. <modules runAllManagedModulesForAllRequests="true"/>
  37. </system.webServer>
  38. </configuration>

6、新建winform客户端进行测试

7、添加服务端引用:


小注:

今天在vs2015中新建WCF类库,又能找到服务了

8、客户端代码如下:

  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Data;
  5. using System.Drawing;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Windows.Forms;
  9. using System.ServiceModel;
  10. using FormTest.CalculateService;
  11. namespace FormTest
  12. {
  13. public partial class Form1 : Form
  14. {
  15. public Form1()
  16. {
  17. InitializeComponent();
  18. }
  19. private void button1_Click(object sender, EventArgs e)
  20. {
  21. // Construct InstanceContext to handle messages on callback interface
  22. InstanceContext instanceContext = new InstanceContext(new CallbackHandler());
  23. // Create a client
  24. CalculateService.CalculateServiceClient client = new CalculateService.CalculateServiceClient(instanceContext);
  25. client.GetData("客户端 传入 参数 测试 GetData");
  26. MessageBox.Show("GetData 调用完成!");
  27. //WCF 数据契约的用途
  28. CompositeType composite = client.Clear();
  29. MessageBox.Show("Clear 调用成功 \r\n" + composite.StringValue);
  30. }
  31. }
  32. /// <summary>
  33. /// 以为能找到服务端里的ICalculatorDuplexCallback接口,谁知道服务端的接口ICalculatorDuplexCallback
  34. /// 是ICalculateServiceCallback的形式出现在客户端的
  35. /// </summary>
  36. //修改回调回调函数的通知线程,将其改为在非UI线程中执行。
  37. //WCF中可以通过在客户端回调函数类中的CallbackBehaviorAttribute中控制这一行为
  38. //从而解决UI死锁问题
  39. [CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
  40. public class CallbackHandler : CalculateService.ICalculateServiceCallback
  41. {
  42. public void ComplexCalculate(string result)
  43. {
  44. MessageBox.Show(result.ToString());
  45. }
  46. public string GetComplexCalculateResult(string result)
  47. {
  48. return result;
  49. }
  50. }
  51. }

小注:
在WCF回调中需要注意死锁问题
1、如果WCF中暴露出来的操作,没有返回值,则可以通过就是设置回调操作
IsOneWay=true,这样回调以后立即释放服务实例,不需要等待客户端响应消息,也可以避免死锁。
2、如果WCF中暴露出来的操作,有返回值,则需要通过,修改服务的ServiceBehavior的ConcurrencyMode为Reentrant或Multiple即可。
此时,服务端的死锁问题搞定了。
下面就需要考虑客户端的死锁问题了
客户端的死锁问题,通过在客户端回调函数类中的CallbackBehaviorAttribute中控制这一行为

死锁具体分析可以参考:点击打开链接

demo代码:点击打开链接

服务端死锁时的提示信息:

  1. 未处理 System.ServiceModel.FaultException`1
  2. HResult=-2146233087
  3. Message=此操作将死锁,因为在当前邮件完成处理以前无法收到答复。如果要允许无序的邮件处理,则在 ServiceBehaviorAttribute 上指定可重输入的或多个 ConcurrencyMode。
  4. Source=mscorlib
  5. Action=http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher/fault
  6. StackTrace:
  7. Server stack trace:
  8. 在 System.ServiceModel.Channels.ServiceChannel.ThrowIfFaultUnderstood(Message reply, MessageFault fault, String action, MessageVersion version, FaultConverter faultConverter)
  9. 在 System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)
  10. 在 System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
  11. 在 System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
  12. 在 System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
  13. Exception rethrown at [0]:
  14. 在 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
  15. 在 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
  16. 在 FormTest.CalculateService.ICalculateService.GetData(Int32 value)
  17. 在 FormTest.CalculateService.CalculateServiceClient.GetData(Int32 value) 位置 E:\WorkSpace\WorkSpaceTest\WcfDuplexTest\FormTest\Service References\CalculateService\Reference.cs:行号 124
  18. 在 FormTest.Form1.button1_Click(Object sender, EventArgs e) 位置 E:\WorkSpace\WorkSpaceTest\WcfDuplexTest\FormTest\Form1.cs:行号 27
  19. 在 System.Windows.Forms.Control.OnClick(EventArgs e)
  20. 在 System.Windows.Forms.Button.OnClick(EventArgs e)
  21. 在 System.Windows.Forms.Button.OnMouseUp(MouseEventArgs mevent)
  22. 在 System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
  23. 在 System.Windows.Forms.Control.WndProc(Message& m)
  24. 在 System.Windows.Forms.ButtonBase.WndProc(Message& m)
  25. 在 System.Windows.Forms.Button.WndProc(Message& m)
  26. 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
  27. 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
  28. 在 System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
  29. 在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
  30. 在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
  31. 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
  32. 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
  33. 在 System.Windows.Forms.Application.Run(Form mainForm)
  34. 在 FormTest.Program.Main() 位置 E:\WorkSpace\WorkSpaceTest\WcfDuplexTest\FormTest\Program.cs:行号 18
  35. 在 System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
  36. 在 System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
  37. 在 Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
  38. 在 System.Threading.ThreadHelper.ThreadStart_Context(Object state)
  39. 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
  40. 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
  41. 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
  42. 在 System.Threading.ThreadHelper.ThreadStart()
  43. InnerException:

小注:

WCF 双工模式的更多相关文章

  1. 利用WCF双工模式实现即时通讯

    概述 WCF陆陆续续也用过多次,但每次都是浅尝辄止,以将够解决问题为王道,这几天稍闲,特寻了些资料看,昨晚尝试使用WCF的双工模式实现了一个简单的即时通讯程序,通过服务端转发实现客户端之间的通讯.这只 ...

  2. [SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端

    原文:[SignalR]SignalR与WCF双工模式结合实现服务端数据直推浏览器端 之前开发基于WinForm监控的软件,服务端基于Wcf实现,里面涉及双工模式,在客户端里面,采用心跳包机制保持与服 ...

  3. WCF学习之旅—TCP双工模式(二十一)

    WCF学习之旅—请求与答复模式和单向模式(十九) WCF学习之旅—HTTP双工模式(二十) 五.TCP双工模式 上一篇文章中我们学习了HTTP的双工模式,我们今天就学习一下TCP的双工模式. 在一个基 ...

  4. WCF学习之旅—HTTP双工模式(二十)

    WCF学习之旅—请求与答复模式和单向模式(十九) 四.HTTP双工模式 双工模式建立在上文所实现的两种模式的基础之上,实现客户端与服务端相互调用:前面介绍的两种方法只是在客户端调用服务端的方法,然后服 ...

  5. WCF服务创建与使用(双工模式)

    昨天发布了<WCF服务创建与使用(请求应答模式)>,今天继续学习与强化在双工模式下WCF服务创建与使用,步骤与代码如下. 第一步,定义服务契约(Service Contract),注意Se ...

  6. 使用wcf的双工模式做的一个控制台聊天app

    //wcf 服务 using System; using System.Collections.Generic; using System.Linq; using System.Runtime.Ser ...

  7. WCF入门教程3——WCF通信模式

    本章内容 请求/响应模式 单工模式 双工模式 WCF异步调用 请求与响应模式 请求/响应     请求/响应通信是指客户端向服务端发送消息后,服务端会向客户端发送响应.这也意味着在接收到服务的响应以前 ...

  8. WCF双工通讯以及客户端间的间接通讯

    由于学习计划安排不当,对WCF的认知一直停滞不前,最近工作上又用回了WCF,重拾一下,看到蒋老师介绍双工通讯的博文,实践一下,积累一下.原想着WCF的双工通讯就是原本的客户端能调用服务端的方法之余,服 ...

  9. Wcf 双工通信的应用

    概述 双工(Duplex)模式的消息交换方式体现在消息交换过程中,参与的双方均可以向对方发送消息.基于双工MEP消息交换可以看成是多个基本模式下(比如请求-回复模式和单项模式)消息交换的组合.双工ME ...

随机推荐

  1. POJ 2127 Greatest Common Increasing Subsequence -- 动态规划

    题目地址:http://poj.org/problem?id=2127 Description You are given two sequences of integer numbers. Writ ...

  2. 工厂方法(Factory Pattern)

    工厂方法模式定义:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个.工厂方法让类把实例化推迟到子类.(注:“决定”不是指模式允许子类本身在运行时做决定,而是指在编写创建者类时,不需要知道实际 ...

  3. source和.命令的区别

    source FileName 作用:在当前bash环境下读取并执行FileName中的命令. 注:该命令通常用命令“.”来替代. 如:source .bash_rc 与 . .bash_rc 是等效 ...

  4. mysql基本知识

    最大连接数show variables max_connections; select VARIABLE_VALUE from information_schema.GLOBAL_VARIABLES ...

  5. jquery图片无缝滚动代码左右 上下无缝滚动图片

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. apache开启gzip的方法

    在Apache中开启gzip压缩方法为: 1. 在httpd.conf 或者博客根目录的.htaccess文件中加入如下规则(Apache服务器需要支持 mod_deflate) 本文出处参考:htt ...

  7. MYSQL Error 2006HY000:MySQL server has gone away的解决方案

    MySQL server has gone away有几种情况. 1.应用程序(比如PHP)长时间的执行批量的MYSQL语句. 最常见的就是采集或者新旧数据转化. 解决方案: 在my.cnf文件中添加 ...

  8. eclipse中配置maven的web项目

    提高效率,一般都会使用IED如eclipse来帮助开发.eclipse中单独建立一个web项目或者是maven项目是可以通过插件很容易完成的,但是如果要结合2者,就需要先建立一个,然后再转换或使原型. ...

  9. Python设计模式——设计原则

    1.单一职责原则:每个类都只有一个职责,修改一个类的理由只有一个 2.开放-封闭远程(OCP):开放是指可拓展性好,封闭是指一旦一个类写好了,就尽量不要修改里面的代码,通过拓展(继承,重写等)来使旧的 ...

  10. mysql数据库乱码

    问题:mysql数据库的编码都设置为utf8的情况下,用jdbc往数据库中插入数据时仍然乱码, 解决方法:在jdbc的中加上参数characterEncoding=utf8&useUnicod ...