消息隊列不同于傳統的請求響應模式,它是客戶端把消息發送給請求消息隊列,服務可以稍后對消息進行處理并把處理結果發送給響應隊列,而后客戶端從響應隊列讀取服務處理后的消息。而且使用消息隊列可以使客戶端實現脫機工作。脫機應用程序必須有本地緩存數據,要采用異步通訊而且要把消息持久化,在與服務器聯機后將消息發送出去。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元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
