[老老实实学WCF] 第九篇 消息通信模式(上) 请求应答与单向

原文:[老老实实学WCF] 第九篇 消息通信模式(上) 请求应答与单向

老老实实学WCF

第九篇 消息通信模式(上) 请求应答与单向

 

通过前两篇的学习,我们了解了服务模型的一些特性如会话和实例化,今天我们来进一步学习服务模型的另一个重要特性:消息通信模式。

 

WCF的服务端与客户端在通信时有三种模式:单向模式、请求/应答模式和双工模式。

 

如果选用了单向模式,调用方在向被调用方进行了调用后不期待任何回应,被调用方在执行完调用后不给调用方任何反馈。如客户端通过单向模式调用了一个服务端的操作后,就去干别的了,不会等待服务端给他任何响应,他也无从得知调用是否成功,甚至连发生了错误也全然不知。这种模式的特点是,客户端在调用操作后立即返回,从客户端角度看,用户操作的响应是非常快的,只是客户端无法得知调用结果。

 

如果选用了请求/应答模式,客户端向服务端发出调用后会一直等待服务端的回复,服务端在执行完操作后会把结果返回给客户端,即使服务操作签名返回值为void,服务端还是会返回一条空消息,告诉客户端调用完成了,客户端在接到返回后才会从调用方法返回继续进行下面的工作。这种模式的特点是客户端总是可以知道服务执行的情况,如果出错,错误也会返回,客户端对服务的执行监控的很好,但是由于在服务返回之前客户端会一直等待,所以如果服务端的服务执行时间比较长的话,客户端这边的用户响应就会很慢,如果客户端对服务的调用与用户界面在同一线程,在用户看来,应用程序就死在那里了。

 

如果选用了双工模式,客户端和服务端都可以单独的向对方发送消息调用,其实这种模式是在单向模式基础上进行的,两边的调用都是单向调用,但是两边都可以独立的进行,谁也不用等待谁,这种模式比较复杂一些,我们在下一篇再详细的研究。

 

1. 如何设置消息通信模式。

双工模式有其他的设置方式,单行模式和请求应答模式的设置位置是相同的,就是通过修改操作协定的OperationContract属性的IsOneWay属性来设置。如下面的代码将HelloWCF操作协定设置为了单向模式:

    [ServiceContract]
    public interface IHelloWCF
    {
        [OperationContract(IsOneWay=true)]
        void HelloWCF();
    }

如果不配置IsOneWay属性,那么他默认是False的,也就是说默认的消息通信模式是请求/应答模式,除非我们显式的指定为单向模式。

下面的代码将HelloWCF操作协定设置为了请求/应答模式:

    [ServiceContract]
    public interface IHelloWCF
    {
        [OperationContract(IsOneWay=false)]
        void HelloWCF();
    }

由于是默认值,IsOneWay属性不配置也是可以的。

 

注意,在单向模式下,返回值必须是void,并且不能使用任何Out或Ref的方式返回参数值,也就是说不能以任何手段返回任何值,这是基础结构所不允许的,这样做会导致服务端抛出异常。而在请求/应答模式下,这些都是可以的,即使没有返回值(返回值为void),返回消息也会照样发送,只不过是个空消息。

2. 两种模式的例子

首先我们看一个请求/应答模式的例子,我用的还是前几篇中使用的IIS宿主服务的例子,如果你忘了,翻回去熟悉一下。

我们让服务端的HelloWCF在返回"Hello WCF!"字符串之前,先磨蹭一会,让他在线程上休眠一会儿。

HelloWCFService.CS的源代码如下:

using System;
using System.ServiceModel;

namespace LearnWCF
{
    [ServiceContract]
    public interface IHelloWCF
    {
        [OperationContract(IsOneWay=false)]
        string HelloWCF();
    }  

    public class HelloWCFService : IHelloWCF
    {
        private int _Counter;
        public string HelloWCF()
        {
            System.Threading.Thread.Sleep(3000);
            return "Hello WCF!";
        }
    }
}

没什么变化,就是让他在线程上Sleep 3秒。

下面是Web.Config文件,也没什么变化:

<configuration>
  <system.serviceModel>
    <services>
      <service name="LearnWCF.HelloWCFService" behaviorConfiguration="metadataExchange">
        <endpoint address="" binding="wsHttpBinding" contract="LearnWCF.IHelloWCF"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="metadataExchange">
          <serviceMetadata httpGetEnabled="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>
</configuration>

下面是SVC文件,就一行代码,指示了这是个WCF服务,并指定了后台类型:

<%@ServiceHost language=c# Debug="true" Service="LearnWCF.HelloWCFService"%>

 

把SVC文件和Web.Config文件放在网站根文件夹下,CS文件放在App_Code文件夹下,启动IIS,服务就寄宿好了,如果你忘记了如何在IIS中寄宿,马上翻回第三篇熟悉一下。

 

用SVCUTIL.EXE或添加服务引用来生成客户端,为了能看出调用的时间,我们在调用前和调用后分别把时间输出来。Program.cs代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ServiceModel;

namespace ConsoleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Services.HelloWCFClient client = new Services.HelloWCFClient();
            Console.WriteLine(DateTime.Now.ToLongTimeString());
            Console.WriteLine(client.HelloWCF());
            Console.WriteLine(DateTime.Now.ToLongTimeString());
            Console.ReadLine();
        }
    }
}

F5运行一下,结果如下:

可以看到,整个调用花费了4秒钟,除了服务方法中Sleep了3秒,建立会话通讯什么的还用了1秒,在服务端方法Sleep的时候,客户端一直在等待。

 

接下来,我们再看单向模式的情况,我们修改一下服务协定的代码,让其采用单向模式,但是注意,此时不能有返回值了,必须设为void,服务方法中就是睡3秒,其他的什么也不做。

using System;
using System.ServiceModel;

namespace LearnWCF
{
    [ServiceContract]
    public interface IHelloWCF
    {
        [OperationContract(IsOneWay=true)]
        void HelloWCF();
    }  

    public class HelloWCFService : IHelloWCF
    {
        private int _Counter;
        public void HelloWCF()
        {
            System.Threading.Thread.Sleep(3000);
        }
    }
}

客户端需要重新下载一下元数据或更新一下服务引用,因为服务协定的内容变了,客户端Program.CS代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ServiceModel;

namespace ConsoleClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Services.HelloWCFClient client = new Services.HelloWCFClient();
            Console.WriteLine(DateTime.Now.ToLongTimeString());
            client.HelloWCF();
            Console.WriteLine(DateTime.Now.ToLongTimeString());
            Console.ReadLine();
        }
    }
}

F5看看结果:

可以看到只用了1秒,客户端与服务端建立会话后把调用送出就立即返回了,没有等待服务端睡那三秒,当然此时的客户端也根本就不知道服务端在做什么。

 

注意,请求应答模式是需要会话支持的,必须使用支持会话的绑定,而且服务协定的SessionMode必须至少为Allowed,服务类的ServiceBehavior的InstanceContextMode必须是PerSession,我们在这里没有配置,因为他们是默认的,但是我们必须知道他们需要这样的配置才能支持请求/应答模式。

 

如果你在试验中遇到了莫名其妙的问题,尝试把客户端服务引用全部删掉重新添加服务引用,因为有的时候更新服务引用不总是那么好用。

3. 总结

通过这一篇的学习,我们了解了消息通讯的两种基本模式,在这个基础上还有更加复杂的双工通讯模式,我们在下一篇中详细研究。

 

 

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-09-08 16:54:09

[老老实实学WCF] 第九篇 消息通信模式(上) 请求应答与单向的相关文章

[老老实实学WCF] 第十篇 消息通信模式(下) 双工

原文:[老老实实学WCF] 第十篇 消息通信模式(下) 双工 老老实实学WCF 第十篇 消息通信模式(下) 双工   在前一篇的学习中,我们了解了单向和请求/应答这两种消息通信模式.我们知道可以通过配置操作协定的IsOneWay属性来改变模式.在这一篇中我们来研究双工这种消息通信模式.   在一定程度上说,双工模式并不是与前面两种模式相提并论的模式,双工模式的配置方法同前两者不同,而且双工模式也是基于前面两种模式之上的.   在双工模式下,服务端和客户端都可以独立地调用对方,谁都不用等待谁的答复

[老老实实学WCF] 第一篇 Hello WCF

原文:[老老实实学WCF] 第一篇 Hello WCF 老老实实学WCF  第一篇 Hello WCF   WCF(Windows Communication Foundation)是微软公司推出的面向服务技术的集大成者,涵盖继承了其之前发布的所有的分布式应用程序的编程模型,涉及面之广,技术之复杂,结构之零散,让我们初学这门技术的菜鸟时常有无处下手的感觉,此系列博文系笔者艰难探索WCF技术过程的学习笔记,笔者抱着老老实实的态度,力图扎扎实实,循序渐进地学好这门技术,文中难免有疏漏和错误之处,还请

[老老实实学WCF] 第五篇 再探通信--ClientBase

原文:[老老实实学WCF] 第五篇 再探通信--ClientBase 老老实实学WCF 第五篇 再探通信--ClientBase   在上一篇中,我们抛开了服务引用和元数据交换,在客户端中手动添加了元数据代码,并利用通道工厂ChannelFactory<>类创建了通道,实现了和服务端的通信.然而,与服务端通信的编程模型不只一种,今天我们来学习利用另外一个服务类ClientBase<>来完成同样的工作,了解了这个类的使用方法,我们对服务引用中的关键部分就能够理解了.   Client

[老老实实学WCF] 第八篇 实例化

原文:[老老实实学WCF] 第八篇 实例化 老老实实学WCF 第八篇 实例化   通过上一篇的学习,我们简单地了解了会话,我们知道服务端和客户端之间可以建立会话连接,也可以建立非会话连接,通信的绑定和服务协定的ServiceContract 的SessionMode属性共同决定了连接是否是会话的.会话连接在会话保持阶段服务端可以记住客户端,而非会话连接则不会,相同客户端的多次调用会被认为是不同的客户端发起的.   会话这个特性是许多其他特性的基础,例如我们今天要学习的实例化.连接是否是会话对实例

[老老实实学WCF] 第六篇 元数据交换

原文:[老老实实学WCF] 第六篇 元数据交换 老老实实学WCF 第六篇 元数据交换   通过前两篇的学习,我们了解了WCF通信的一些基本原理,我们知道,WCF服务端和客户端通过共享元数据(包括服务协定.服务器终结点信息)在两个终结点上建立通道从而进行通信.我们通过手写代码(或配置)的方式为服务端编写了元数据信息,没有借助元数据交换就实现了通信.然而在实际应用中,元数据往往是很多的,而且重复编写元数据的工作也是不值得的,因此必然会用到元数据交换的方式让客户端获取元数据,本篇我们就来进一步了解一下

[老老实实学WCF] 第三篇 在IIS中寄存服务

原文:[老老实实学WCF] 第三篇 在IIS中寄存服务 老老实实学WCF 第三篇 在IIS中寄宿服务   通过前两篇的学习,我们了解了如何搭建一个最简单的WCF通信模型,包括定义和实现服务协定.配置服务.寄宿服务.通过添加服务引用的方式配置客户端并访问服务.我们对WCF的编程生命周期有了一个最基本的了解.   在前两篇中演示的例子,一定要力求背着做下来,包括源程序.配置文件都要背着一行行的手写下来,这样才能有深刻的体会.WCF的知识零散复杂,必须扎扎实实的学习和练习.如果你还没有做到了然于胸,现

15天玩转redis —— 第九篇 发布/订阅模式

本系列已经过半了,这一篇我们来看看redis好玩的发布订阅模式,其实在很多的MQ产品中都存在这样的一个模式,我们常听到的一个例子 就是邮件订阅的场景,什么意思呢,也就是说100个人订阅了你的博客,如果博主发表了文章,那么100个人就会同时收到通知邮件,除了这个 场景还能找到其他场景么,当然有啦,你想想,如果你要在内存里面做一个读写分离的程序,为了维持数据的完整性,你是不是需要保证在写入 的时候,也要分发到各个读内存的程序中呢?所以说场景还是很多的,在于你的挖掘~~~ 下面还是从基本命令入手: 一

十五天精通WCF——第六天 你必须要了解的3种通信模式

wcf已经说到第六天了,居然还没有说到这玩意有几种通信模式,惭愧惭愧,不过很简单啦,单向,请求-响应,双工模式,其中的第二种"请求-响应" 模式,这个大家不用动脑子都清楚,这一篇我大概来分析下. 一:"请求-响应"模式 如果你看了我上一篇的博文,你应该非常清楚这种类似"本地调用"的方式,wcf同样也分为"同步"和"异步"两种,不过不管是异步还是同步,最终都逃 不过是"请求-响应"这个事实

《WCF技术内幕》翻译14:第1部分_第3章_消息交换模式、拓扑与编排…

<WCF技术内幕>翻译14:第1部分_第3章_消息交换模式.拓扑与编排:消息交换模式(MEP) 第3章:消息交换模式.拓扑和编排 当设计消息应用系统的时候,有必要考虑一下消息是怎样在发送者.中介者 和接受者(前面章节介绍了这些消息参与者)流转的.系统中消息交换可能性的 波动的值可以被不同程度地详细描述.这些不同级别的细节就是总所周知的消息 交换模式(MEPS).消息拓扑和消息编排[老徐备注1].当从总体来看时,这 三个级别的细节让我们抽象地描述任何消息场景.本章会详细剖析消息交换模式 (MEP