消息隊列不同于傳統的請求響應模式,它是客戶端把消息發送給請求消息隊列,服務可以稍后對消息進行處理并把處理結果發送給響應隊列,而后客戶端從響應隊列讀取服務處理后的消息。而且使用消息隊列可以使客戶端實現脫機工作。脫機應用程序必須有本地緩存數據,要采用異步通訊而且要把消息持久化,在與服務器聯機后將消息發送出去。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。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

