WCF中队列服务详解
WCF中队列服务详解
一、引言
在前面的WCF服务中,它都要求服务与客户端两端都必须启动并且运行,从而实现彼此间的交互。然而,还有相当多的情况希望一个面向服务的应用中拥有离线交互的能力。WCF通过服务队列的方法来支持客户端和服务之间的离线工作,客户端将消息发送到一个队列中,再由服务对它们进行处理。下面让我们具体看看WCF中的队列服务。
二、WCF队列服务的优势
在介绍WCF队列服务之前,首先需要了解微软消息队列(MSMQ)。MSMQ是在多个不同应用之间实现相互通信的一种异步传输模式,相互通信的应用可以分布在同一台机器,也可以分布在相连的网络环境。它的实现原理是:客户端将消息发送到一个容器中,然后把它保存到一个系统公用空间的消息队列(Message Queue)中,本地或异地的服务再从该队列中取出发送给它的消息进行处理。更多详细内容可以参考我的博文:跟我一起学WCF(1)——MSMQ消息队列。
WCF框架对MSMQ进行了集成和扩展,MSMQ支持离线消息模式,并且在WCF框架下,提供了基于http桥的internet网络队列服务的调用扩展。从而赋予了WCF队列服务以下几点优势:
- 支持离线消息模式。因为WCF框架集成了MSMQ,所以WCF队列服务自然也支持离线消息。
- 支持将操作分解。WCF支持将工作分解为多个操作放入队列中,可改善系统的可用性和吞吐量。
- 提供对失败的事务做善后处理。当我们的业务事务需要几个小时或几天完成的时候,我们通常将它分为至少2个事务。第一个事务将需要立即完成的工作放入队列,而第二个事务用于验证第一个事务是否成功,并在必要的情况下对失败的事务进行善后处理。
- 支持负载平衡。可以把过载的客户端请求放入队列,空闲的时候进行处理,这样可以平衡系统的吞吐量,改善性能。
三、WCF队列服务通信框架
WCF使用NetMsmqBinding来支持消息队列通信。当客户端调用服务时,客户端消息会被封装为MSMQ消息,发送到系统公用的消息队列中,服务宿主在运行状态下会启动通道监听器来检测消息队列消息,如果发现对应的消息,则会从队列里取出消息,使用分发器转发给对应的服务,具体的通信框架如下图所示:

如果宿主离线,消息会被放入队列,等待下一次宿主联机时,在执行消息分发给指定WCF服务处理。
另外WCF还提供了MsmqIntegrationBinding类,该类用于需要将WCF 应用和现有的基于MSMQ的应用集成的情况。WCF应用可利用该绑定向现有的MSMQ应用程序发生消息,或从这些应用程序接收消息。
四、利用WCF队列服务来实现离线操作
前面介绍WCF队列服务的优势和它的通信框架,下面具体通过一个例子来诠释WCF队列服务的实现。我们还是按照前面文章介绍的三个步骤来实现该实例。
第一步:定义契约和实现服务。具体的实现代码如下所示:

1 [ServiceContract]
2 public interface IWCFMSMQService
3 {
4 // 操作契约,必须为单向操作
5 [OperationContract(IsOneWay = true)]
6 void SayHello(string message);
7 }
8
9 // 契约实现
10 public class WCFMSMQService : IWCFMSMQService
11 {
12 public WCFMSMQService()
13 {
14 Console.WriteLine("WCF MSMQ Service instance was created at: {0}", DateTime.Now);
15 }
16
17 #region IOrderProcessor Members
18
19 [OperationBehavior(TransactionScopeRequired = true, TransactionAutoComplete = true)]
20 public void SayHello(string message)
21 {
22 Console.WriteLine("Hello! {0},调用WCF操作的时间为:{1}", message, DateTime.Now);
23 }
24
25 #endregion
26 }

上面代码需要注意一点:WCF操作必须定义为单向操作,因为要实现的是一个队列服务,其特点为异步、离线,无返回值。所以要设置IsOneWay属性为true。
第二步:实现宿主。这里仍然使用控制台应用程序作为WCF队列服务的宿主,具体的实现代码如下所示:

1 namespace WCFConsoleHost
2 {
3 class Program
4 {
5 static void Main(string[] args)
6 {
7 string path = @".\private$\LearningHardWCFMSMQ";
8 if (!MessageQueue.Exists(path))
9 {
10 MessageQueue.Create(path, true);
11 }
12
13 using (ServiceHost host = new ServiceHost(typeof(WCFMSMQService)))
14 {
15 host.Opened += delegate
16 {
17 Console.WriteLine("Service has begun to listen\n\n");
18 };
19
20 host.Open();
21
22 Console.Read();
23 }
24 }
25 }
26 }

对应的配置信息如下所示:

<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="msmqServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<netMsmqBinding>
<binding name="msmqBinding">
<security>
<transport msmqAuthenticationMode="None" msmqProtectionLevel="None"/>
<message clientCredentialType="None"/>
</security>
</binding>
</netMsmqBinding>
</bindings>
<services>
<service behaviorConfiguration="msmqServiceBehavior" name="WCFContractAndService.WCFMSMQService">
<endpoint address="net.msmq://localhost/private/LearningHardWCFMSMQ" binding="netMsmqBinding"
bindingConfiguration="msmqBinding" contract="WCFContractAndService.IWCFMSMQService" />
<!--发布服务元数据的终结点-->
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:9003/" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

第三步:WCF客户端的实现。首先以管理员权限启动宿主,然后通过添加服务引用的方式来生成代理客户端类,具体在添加服务引用窗口地址栏输入:http://localhost:9003/mex来添加服务引用,添加服务引用成功后将生成代理类,通过代理类来对WCF服务进行访问,具体的实现代码如下所示:

1 namespace WCFClient
2 {
3 class Program
4 {
5 static void Main(string[] args)
6 {
7 WCFMSMQServiceClient proxy = new WCFMSMQServiceClient("NetMsmqBinding_IWCFMSMQService");
8 using (TransactionScope scope = new TransactionScope(TransactionScopeOption.Required))
9 {
10 Console.WriteLine("WCF First Call at:{0}", DateTime.Now);
11 proxy.SayHello("World");
12
13 Thread.Sleep(2000);//客户端休眠两秒,继续下一次调用
14 Console.WriteLine("WCF Second Call at:{0}", DateTime.Now);
15 proxy.SayHello("Learning Hard");
16
17 scope.Complete();
18 }
19
20 Console.Read();
21 }
22 }
23 }

经过上面三步,我们就完成了一个WCF队列服务程序。下面让我们看看该程序的运行结果。
因为WCF队列服务是对MSMQ的集成和扩展,所以此时该程序客户端可以在WCF服务离线的情况也可运行,即WCF服务宿主不启动,客户端也可以正常运行,这点与前面介绍的WCF程序完成不同,因为前面的WCF程序,如果宿主程序不启动而直接启动客户端程序,则客户端程序运行时将会发生异常。该程序之所以不会发生异常的原因在于,此时客户端程序是直接与消息队列进行交互的,而不是直接与WCF服务进行交互。此时只运行WCF客户端,你将看到如下图所示的运行结果:

同时,你在消息队列的专有队列的队列消息中将看到两条未处理的消息信息,具体效果如下图所示:

因为WCF服务宿主还没有启动,所以客户端发送的消息信息还没有被取出处理,接下来,我们启动下服务宿主来对队列中的消息进行处理,此时你可以选择关闭客户端(当然你也可以不关闭)。具体的WCF服务宿主的运行结果如下图所示:

此时,如果刷新消息队列的专有队列中的队列消息,你将看不到任何消息了,这是因为WCF服务从消息队列取出消息进行处理了,即消息完成了出队的操作。
五、总结
到这里,WCF队列服务的介绍也就结束了。本文主要介绍了WCF集成了MSMQ的功能,WCF可以利用netMsmqBinding来实现离线服务。其实现程序与MSMQ程序实现差不多,关于MSMQ的相关内容也可以参考我的另一篇博文:跟我一起学WCF(1)——MSMQ消息队列。在下一篇博文中将分享WCF对Rest服务的支持和实现。
本文所有源码:WCFMSMQService.zip
WCF中队列服务详解的更多相关文章
- 跟我一起学WCF(11)——WCF中队列服务详解
一.引言 在前面的WCF服务中,它都要求服务与客户端两端都必须启动并且运行,从而实现彼此间的交互.然而,还有相当多的情况希望一个面向服务的应用中拥有离线交互的能力.WCF通过服务队列的方法来支持客户端 ...
- Android中Service(服务)详解
http://blog.csdn.net/ryantang03/article/details/7770939 Android中Service(服务)详解 标签: serviceandroidappl ...
- 缓存架构中的服务详解!SpringBoot中二级缓存服务的实现
创建缓存服务 创建缓存服务接口项目 创建myshop-service-redis-api项目,该项目只负责定义接口 创建项目的pom.xml: <?xml version="1.0&q ...
- winxp计算机管理中服务详解
winxp计算机管理中服务详解01 http://blog.sina.com.cn/s/blog_60f923b50100efy9.html http://blog.sina.com.cn/s/blo ...
- (转)python标准库中socket模块详解
python标准库中socket模块详解 socket模块简介 原文:http://www.lybbn.cn/data/datas.php?yw=71 网络上的两个程序通过一个双向的通信连接实现数据的 ...
- Android中Intent组件详解
Intent是不同组件之间相互通讯的纽带,封装了不同组件之间通讯的条件.Intent本身是定义为一个类别(Class),一个Intent对象表达一个目的(Goal)或期望(Expectation),叙 ...
- Liunx中fstab文件详解
Liunx中fstab文件详解 /etc/fstab是用来存放文件系统的静态信息的文件.位于/etc/目录下,可以用命令less /etc/fstab 来查看,如果要修改的话,则用命令 vi /etc ...
- 【转】SSH服务详解
[转]SSH服务详解 第1章 SSH服务 1.1 SSH服务协议说明 SSH 是 Secure Shell Protocol 的简写,由 IETF 网络工作小组(Network Working Gro ...
- springcloud中Feign配置详解
Spring Cloud中Feign配置详解 到目前为止,小伙伴们对Feign的使用已经掌握的差不多了,我们在前文也提到Feign是对Ribbon和Hystrix的整合,那么在Feign中,我们要如何 ...
随机推荐
- C#程序(含多个Dll)合并成一个Exe
把C#程序(含多个Dll)合并成一个Exe的超简单方法 开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了. 但是,很多时候我们本想开发一款只需要一 ...
- 据序和中序序列或者也许为了一个二进制序列,恢复二进制和打印图像(c语言)
首先要预购和序,以恢复它: 1.首先,我们使用的是递归的方式来完成 2.递归的最小单位:一个空的树和书的前言和第一序.该序列的第一个元素是树的第一序列根,调用这种方法 3.递归的终止条件是.当这棵树的 ...
- Gradle digest
task类型 copy task copyFiles(type: Copy) { from 'resources' into 'target' include '**/*.xml', '**/*.tx ...
- CoffeeScript NgComponent
Angular遇上CoffeeScript - NgComponent封装 CoffeeScript是基于JavaScript的一门扩展小巧语言,它需要编译成JavaScript,然后再运行与浏览器或 ...
- 【MongoDB】在windows平台mongodb切片集群(三)
在过去的两年我们博客详细阐述了零碎工作集群和打造过程.在这篇博客中,我们主要分析测试结果一起支离破碎集群. 首先来看看碎片集群的每个状态.你可以看出来复制集A和B都是正常的: 一.开启分片集合 开启一 ...
- UVA - 11324 The Largest Clique 强连通缩点+记忆化dp
题目要求一个最大的弱联通图. 首先对于原图进行强连通缩点,得到新图,这个新图呈链状,类似树结构. 对新图进行记忆化dp,求一条权值最长的链,每一个点的权值就是当前强连通分量点的个数. /* Tarja ...
- java通用抹去魔,在边界行动,擦除补偿
java通用抹去魔 package org.rui.generics.erasure; public class HasF { public void f(){ System.out.println( ...
- 【leetcode】Clone Graph(python)
类似于二叉树的三种遍历,我们能够基于遍历的模板做非常多额外的事情,图的两种遍历,深度和广度模板相同也能够做非常多额外的事情,这里举例利用深度优先遍历的模板来进行复制,深度优先中,我们先訪问第一个结点, ...
- 彩色图像上执行Mean Shift迭代搜索目标 ,维加权直方图 + 巴氏系数 + Mean Shift迭代
今天要给大家分享的是: 在彩色图像上进行Mean Shift迭代搜索目标 二维加权直方图+巴氏系数+Mean Shift迭代 关于 加权直方图.巴氏系数.Mean Shift迭代 这三者之间的关系请大 ...
- Java学习之路:ArrayList用法
1.什么是ArrayList ArrayList是一个动态数组传奇,使用MSDN声明.那是,Array复杂的版本号,它具有以下优点,例如: 动态的添加和降低元素 实现了ICollection和 ...