Mono 3.0.2 基于双工通信的WCF应用 Demo

双工(Duplex)模式的消息交换方式体现在消息交换过程中,参与的双方均可以向对方发送消息。基于双工MEP消息交换可以看成是多个基本模式下(比如请求-回复模式和单项模式)消息交换的组合。双工MEP又具有一些变体,比如典型的订阅-发布模式就可以看成是双工模式的一种表现形式。双工消息交换模式使服务端回调(Callback)客户端操作成为可能。本文测试Mono 3.0.2/.NET 4对双工(Duplex)模式的WCF支持。

演示基于双工通信的WCF应用是一个简单的计算服务CalculatorService,我们通过单向(One-way)的模式调用CalculuateService(也就是客户端不可能通过回复消息得到计算结果),服务端在完成运算结果后,通过回调(Callback)的方式在客户端将计算结果打印出来。

步骤一:定义服务契约和回调契约

首先进行服务契约的定义,我们照例通过接口(ICalculator)的方式定义服务契约,作用于指定加法运算的Add操作,我们通过OperationContractAttribute特性的IsOneway属性将操作定义成单向的操作,这意味着客户端仅仅是向服务端发送一个运算的请求,并不会通过回复消息得到任何运算结果。

通过在服务端回调客户端操作的方式实现运算结果的输出。客户端调用CalculatorService正常的服务调用,那么在服务执行过程中借助于客户端在服务调用时提供的回调对象对客户端的操作进行回调,从本质上讲是另外一种形式的服务调用。WCF采用基于服务契约的调用形式,客户端正常的服务调用需要服务契约,同理服务端回调客户端依然需要通过描述回调操作的服务契约,我们把这种服务契约称为回调契约。回调契约的类型通过ServiceContractAttribute特性的CallbackContract属性进行指定。

上面代码中服务契约ICalculator的回调契约ICallback定义如下。由于回调契约本质也是一个服务契约,所以定义方式和一般意义上的服务契约基本一样。ICallback定义了一个服务操作DisplayResult用于显示运算结果(前两个参数为执行加法运算的操作数),由于服务端不需要回调的返回值,索性将回调操作也设为单向方法。

步骤二:实现服务

在实现了上面定义的服务契约ICalculator的服务CalculatorService中,实现了Add操作,完成运算和结果显示的工作。结果显示是通过回调的方式实现的,所以需要借助于客户端提供的回调对象(该对象在客户端调用CalculatorService的时候指定,在介绍客户端代码的实现的时候会讲到)。在WCF中,回调对象通过当前OperationContext的GetCallback<T>方法获得(T代表回调契约的类型)。

OperationContext在WCF中是一个非常重要、也是一个十分有用的对象,它代表服务操作执行的上下文。我们可以通过静态属性Current(OperationContext.Current)得到当前的OperationContext。借助OperationContext,我们可以在服务端或者客户端获取或设置一些上下文,比如在客户端可以通过它为出栈消息(outgoing message)添加SOAP报头,以及HTTP报头(比如Cookie)等。在服务端,则可以通过OperationContex获取在客户端设置的SOAP报头和HTTP报头。

步骤三:服务寄宿

我们通过一个控制台应用程序完成对CalculatorService的寄宿工作,并将所有的服务寄宿的参数定义在配置文件中。由于双工通信依赖于一个双工的信道栈,即依赖于一个能够支持双工通信的绑定,在此我们选用了NetTcpBinding,Mono下的wsDualHttpBinding 是不支持的哦,具体可以参看 http://www.mono-project.com/WCF_Development

<?xml version="1.0"?>
<configuration>
    <system.serviceModel>
        <services>
            <service name="DuplexWCF.Service.CalculatorService" behaviorConfiguration="duplexWcf">
                <endpoint address="net.tcp://192.168.10.96:9999/calculator" binding="netTcpBinding"  bindingConfiguration="duplexnetTcpBinding" 
                  contract="DuplexWCF.Contract.ICalculator"/>
            </service>
        </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="duplexWcf">
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
  <bindings> 
     <netTcpBinding>     
       <binding name = "duplexnetTcpBinding">     
         <security mode ="None" />     
       </binding>     
     </netTcpBinding>     
   </bindings>     
  </system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

注: 在WCF预定义绑定类型中,WSDualHttpBinding和NetTcpBinding均提供了对双工通信的支持,但是两者在对双工通信的实现机制上却有本质的区别。WSDualHttpBinding是基于HTTP传输协议的;而HTTP协议本身是基于请求-回复的传输协议,基于HTTP的通道本质上都是单向的。WSDualHttpBinding实际上创建了两个通道,一个用于客户端向服务端的通信,而另一个则用于服务端到客户端的通信,从而间接地提供了双工通信的实现。而NetTcpBinding完全基于支持双工通信的TCP协议。

配置里头<endpoint address="net.tcp://192.168.10.96:9999/calculator" 使用localhost代替具体的ip时候出现无法连接的情况。

MONO_STRICT_MS_COMPLIANT 这个环境变量也不需要了哈,完全原生的Linux支持了哦,之前有网友碰到过WCF的兼容性问题是通过设置环境变量来兼容.NET的。具体可以参看

步骤四:实现回调契约

在客户端程序为回调契约提供实现,在下面的代码中CalculateCallback实现了回调契约ICallback,在DisplayResult方法中对运算结果进行输出。

步骤五:服务调用

接下来实现对双工服务的调用,下面是相关的配置和托管程序。在服务调用程序中,通过DuplexChannelFactory<TChannel>创建服务代理对象,DuplexChannelFactory<TChannel>和ChannelFactory<TChannel>的功能都是一个服务代理对象的创建工厂,不过DuplexChannelFactory<TChannel>专门用于基于双工通信的服务代理的创建。在创建DuplexChannelFactory<TChannel>之前,先创建回调对象,并通过InstanceContext对回调对象进行包装。

在服务寄宿程序启用的情况下,运行客户端程序后,通过服务端执行的运算结果会通过回调客户端的操作显示出来,下面是最终输出的结果。

代码下载

相关文章:

我的WCF之旅(3):在WCF中实现双工通信

Mono WCF Advent Day 11: NetTcpBinding

Using WCF Callback Services Throttling

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ImportSource

并发系列:从原子更新到CPU锁

原子操作在并发编程中是很重要的概念之一,java中的并发的原子操作和各种锁的实现都少不了CAS的影子,本文从AtomicReferenceFieldUpdate...

55990
来自专栏Android开发指南

3.接口文档

30850
来自专栏大内老A

《WCF技术剖析(卷1)》(修订版)目录

第1章 WCF简介 (WCF Overview) 1.1 SOA的基本概念和设计思想 1.2 WCF是对现有Windows平台下分布式通信技术的整合 1.3 构...

18780
来自专栏代码世界

Python数据库连接池DBUtils

 如果没有连接池,使用pymysql来连接数据库时,单线程应用完全没有问题,但如果涉及到多线程应用那么就需要加锁,一旦加锁那么连接势必就会排队等待,当请求比较多...

41810
来自专栏大内老A

WCF技术剖析之十一:异步操作在WCF中的应用(上篇)

按照操作执行所需的资源类型,我们可以将操作分为CPU绑定型(CPU Bound)操作和I/O绑定型(I/O Bound)操作。对于前者,操作的执行主要利用CPU...

22070
来自专栏企鹅号快讯

Koa 框架教程

Node 主要用在开发 Web 应用。这决定了使用 Node,往往离不开 Web 应用框架。 ? Koa就是一种简单好用的 Web 框架。它的特点是优雅、简洁、...

34270
来自专栏Linux驱动

1.Linux电源管理-休眠与唤醒

当我们休眠时,如果想唤醒,则需要添加中断唤醒源,使得在休眠时,这些中断是设为开启的,当有中断来,则会退出唤醒,常见的中断源有按键,USB等.

78120
来自专栏阮一峰的网络日志

Koa 框架教程

Node 主要用在开发 Web 应用。这决定了使用 Node,往往离不开 Web 应用框架。 ? Koa 就是一种简单好用的 Web 框架。它的特点是优雅、简洁...

70350
来自专栏小白课代表

文件搜索利器——Everything

41820
来自专栏C/C++基础

程序内存布局

C/C++程序为编译后的二进制文件,运行时载入内存,运行时内存分布由代码段、初始化数据段、未初始化数据段、堆和栈构成,如果程序使用了内存映射文件(比如共享库、共...

23010

扫码关注云+社区

领取腾讯云代金券