消息队列不同于传统的请求响应模式,它是客户端把消息发送给请求消息队列,服务可以稍后对消息进行处理并把处理结果发送给响应队列,而后客户端从响应队列读取服务处理后的消息。而且使用消息队列可以使客户端实现脱机工作。脱机应用程序必须有本地缓存数据,要采用异步通讯而且要把消息持久化,在与服务器联机后将消息发送出去。WCF是使用NetMsmqBinding来支持消息队列的,传输消息不是通过TCP或HTTP等,而是通过微软消息队列(MSMQ),这是Windows组件,可以通过1)控制面板2)程序和功能:打开或关闭Windows功能3)出现如下界面,点确定即可安装。
安装成功后可以右击我的电脑选择管理而后会有如下界面:
理论也不说那么多了,MSDN上说的很详细,还是写些相对简单清晰的代码的整体上把握下消息队列,有时候看书不是太明白的地方,调试下代码或许会有种豁然开朗的感觉。因为要维护服务端和客户端双向通讯,所以需要两个队列,两个单向操作契约。而客户端的功能既要发送消息到请求消息队列又要从响应消息队列读取响应消息,服务端则需要从调用队列读取消息进行处理,处理后发送的响应消息队列。实际上客户端和服务端并没有直接通讯,而是通过两个队列来进行通讯的。
请求契约:
using
System;
using
System.ServiceModel;
namespace
IFruit
{
[ServiceContract]
public
interface
IFruitService
{
[OperationContract(IsOneWay
=
true
)]
void
GetFruitInfo(
string
fruitName,
string
price);
}
}
请求服务实现:
using
System;
using
System.Messaging;
using
System.ServiceModel;
using
IFruit;
using
IFruitResponse;
namespace
FruitSvc
{
[ServiceBehavior(InstanceContextMode
=
InstanceContextMode.PerCall)]
public
class
FruitService:IFruitService
{
[OperationBehavior(TransactionScopeRequired
=
true
)]
public
void
GetFruitInfo(
string
fruitName,
string
price)
{
string
info
=
string
.Empty;
ExceptionDetail error
=
null
;
try
{
info
=
string
.Format(
"
The Fruit Name Is {0} And Price Is {1}
"
, fruitName, price);
}
catch
(Exception ex)
{
error
=
new
ExceptionDetail(ex);
}
finally
{
//
创建队列
string
queueName
=
"
.\\private$\\FruitResponseQueue
"
;
if
(
!
MessageQueue.Exists(queueName))
{
MessageQueue.Create(queueName,
true
);
}
//
把处理后的消息放到响应消息队列
EndpointAddress address
=
new
EndpointAddress(
"
net.msmq://localhost/private/FruitResponseQueue
"
);
NetMsmqBinding binding
=
new
NetMsmqBinding();
binding.Security.Mode
=
NetMsmqSecurityMode.None;
using
(ChannelFactory
<
IFruitResponseService
>
factory
=
new
ChannelFactory
<
IFruitResponseService
>
(binding,
address))
{
IFruitResponseService response
=
factory.CreateChannel();
response.OnGetFruitInfoCompleted(info, error);
}
}
}
}
}
响应契约:
using
System;
using
System.ServiceModel;
namespace
IFruitResponse
{
[ServiceContract]
public
interface
IFruitResponseService
{
[OperationContract(IsOneWay
=
true
)]
void
OnGetFruitInfoCompleted(
string
fruitInfo, ExceptionDetail error);
}
}
响应服务实现:
using
System;
using
System.Collections.Generic;
using
System.ServiceModel;
using
IFruitResponse;
namespace
FruitResponse
{
//
定义一泛型委托
public
delegate
void
GenericEventHandler
<
T
>
(T t);
[ServiceBehavior(InstanceContextMode
=
InstanceContextMode.PerCall)]
public
class
FruitResponseService : IFruitResponseService
{
//
声明并初始化一委托事件
public
static
event
GenericEventHandler
<
string
>
GetFruitInfoCompleted
=
delegate
{ };
[OperationBehavior(TransactionScopeRequired
=
true
)]
public
void
OnGetFruitInfoCompleted(
string
fruitInfo, ExceptionDetail error)
{
if
(error
==
null
)
{
GetFruitInfoCompleted(fruitInfo);
}
}
}
}
客户端服务寄存:
using
System;
using
System.ServiceModel;
using
System.Messaging;
using
FruitResponse;
using
IFruit;
namespace
FruitClientHost
{
class
Program
{
static
void
Main(
string
[] args)
{
//
GetFruitInfoCompleted发生后调用OnGetFruitInfoCompleted方法
FruitResponseService.GetFruitInfoCompleted
+=
Program.OnGetFruitInfoCompleted;
//
创建两个队列
string
queueName
=
"
.\\private$\\GetFruitInfoQueue
"
;
if
(
!
MessageQueue.Exists(queueName))
{
MessageQueue.Create(queueName,
true
);
}
string
queueName1
=
"
.\\private$\\FruitResponseQueue
"
;
if
(
!
MessageQueue.Exists(queueName1))
{
MessageQueue.Create(queueName1,
true
);
}
//
接收响应消息
ServiceHost fruitHost
=
new
ServiceHost(
typeof
(FruitResponseService),
new
Uri(
"
net.msmq://localhost/private/FruitResponseQueue
"
));
NetMsmqBinding netMsmqBind
=
new
NetMsmqBinding();
netMsmqBind.Security.Mode
=
NetMsmqSecurityMode.None;
fruitHost.AddServiceEndpoint(
typeof
(IFruitResponse.IFruitResponseService), netMsmqBind,
""
);
fruitHost.Open();
//
发送请求消息到请求队列
EndpointAddress address
=
new
EndpointAddress(
"
net.msmq://localhost/private/GetFruitInfoQueue
"
);
NetMsmqBinding binding
=
new
NetMsmqBinding();
binding.Security.Mode
=
NetMsmqSecurityMode.None;
using
(ChannelFactory
<
IFruitService
>
factory
=
new
ChannelFactory
<
IFruitService
>
(binding, address))
{
IFruitService fruit
=
factory.CreateChannel();
fruit.GetFruitInfo(
"
banana
"
,
"
6.00
"
);
}
Console.WriteLine(
"
The Client Is Running ...
"
);
Console.ReadLine();
fruitHost.Close();
}
static
void
OnGetFruitInfoCompleted(
string
fruitInfo)
{
Console.WriteLine(fruitInfo);
}
}
}
服务端服务寄存:
using
System;
using
System.ServiceModel;
using
FruitSvc;
using
IFruit;
namespace
FruitResponseHost
{
class
Program
{
static
void
Main(
string
[] args)
{
ServiceHost fruitServiceHost
=
new
ServiceHost(
typeof
(FruitService),
new
Uri(
"
net.msmq://localhost/private/GetFruitInfoQueue
"
));
NetMsmqBinding netMsmqBind
=
new
NetMsmqBinding();
netMsmqBind.Security.Mode
=
NetMsmqSecurityMode.None;
fruitServiceHost.AddServiceEndpoint(
typeof
(IFruitService), netMsmqBind,
""
);
fruitServiceHost.Open();
Console.WriteLine(
"
The Service Is Running ...
"
);
Console.ReadLine();
fruitServiceHost.Close();
}
}
}
运行程序,先启动客户端,此时的消息可以通过MSMQ管理控制台进行管理:
从管理控制台可以看出GetFruitInfoQueue有一条消息,而后启动服务端:
客户端已经呈现出服务处理后的消息信息,GetFruitInfoQueue的消息已经被服务处理了,消息数目变为0。

