顧名思義微軟消息隊列(MSMQ)是一種給隊列發送消息以便稍後進行處理的方法消息由一個Producer(生產者)應用程序發送出去再由一個Consumer(消費者)應用程序返回
這兩個應用程序可以在同一台機器上在整個網絡中或甚至是位於並不總是連接在一起的不同機器上MSMQ具有故障保險特性因為如果第一次傳送失敗它會重新發送消息這樣可保證你的應用程序消息到達它們的目的地
我將應用一個叫做TechRepublic的隊列當你運行本文下載版本中的樣本實例時如果這個隊列不存在它會自動建立
在前面的一篇文章中Zach Smith說明了如何使用IPC通道在同一台機器上的兩個進程間通信他將在本文中說明如何在同一台機器或網絡上的應用程序間實現進程間通信
訪問MSMQ
通過NET訪問隊列由SystemMessagingMessageQueue對象完成列表A說明了如何在一台名為SRVMESSAGING的計算機上訪問TechRepublic隊列
列表A
MessageQueue queue = new MessageQueue(SRVMESSAGINGTechRepublic);
注要應用這個對象你必須在你的項目中添加一個參考
現在我們有了一個MessageQueue對象這個對象為你提供與隊列交互需要的所有功能
如果隊列不存在你可以調用MessageQueue對象的靜態Create方法編程建立隊列列表B中的代碼說明如何檢查隊列是否存在建立隊列或給隊列添加一個參考
列表B
MessageQueue queue = null;
string queueName = SRVMESSAGINGTechRepublic;
if (MessageQueueExists(queueName))
queue = newMessageQueue(queueName);
else
queue = MessageQueueCreate(queueName false);
改寫隊列
改寫隊列時用到MessageQueueSend方法列表C舉例說明如何向TechRepublic隊列發送一條消息
列表C
queueSend(My message body Message Label);
在這個例子中我們給TechRepublic隊列發送一條正文為My message body的消息並對這個消息應用了一個Message Label標簽消息標簽允許你不需閱讀消息正文就可以分割消息如果從計算機管理控制台中查看隊列還可在隊列消息部分看到這些標簽
讀取隊列
可以使用幾種方法從隊列中讀取消息最常見的情況是從隊列中取出所有消息然後一次性處理它們這時要調用MessageQueueGetAllMessages方法列表D舉例說明如何應用這個方法
列表D
SystemMessagingMessage[] messages = queueGetAllMessages();
foreach (SystemMessagingMessage message in messages)
{
//Do something with the message
}
你也可以用GetMessageEnumerator方法代替上面的MessageQueueGetAllMessages方法雖然這兩個方法的用法類似但GetMessageEnumerator只能向前(forwardonly)對於非常龐大的隊列則應用使用這個方法而不是MessageQueueGetAllMessages方法
這是因為GetAllMessages方法領取所有消息把它們保存在當地內存中而GetMessageEnumerator方法只領取當前消息在本地保存在調用MoveNext時才領取下一條消息列表E舉例說明了GetMessageEnumerator方法的用法這段代碼檢查隊列中的每一條消息再刪除它
列表E
MessageEnumerator enumerator = queueGetMessageEnumerator();
while (enumeratorMoveNext())
enumeratorRemoveCurrent();
在使用GetMessageEnumerator方法時還要考慮另外一個問題即你要訪問隊列中增加的任何新消息即使它們是在你調用GetMessageEnumerator後再增加的這假定新消息被添加到隊列末尾
如果你只希望返回隊列中的第一條消息你應該使用MessageQueueReceive方法這個方法會領取隊列中的第一條消息在這個過程中將它從隊列中刪除由於消息在讀取的時候被刪除你可以確保你的進程是唯一收到消息的進程Receive方法的應用實例如列表F所示
列表F
SystemMessagingMessage message = queueReceive();
可以用Peek方法代替Receive方法Peek方法像Receive方法一樣領取隊列中的第一條消息但是它在隊列中保留消息備份這允許你從隊列中刪除消息之前檢查消息內容Peek的語法與Receive類似
列表G
SystemMessagingMessage message = queuePeek();
發送/接收序列化對象
雖然給隊列發送文本的功能非常有用但隊列還允許你發送可序列化對象這意味著你可以建立一個自定義的NET類實例化它的一個實例將其發送給隊列以便其它應用程序使用要完成這個過程首先得使用XML Serializer序列化被發送的對象然後對序列化對象放到消息的正文中
例如假設我們希望給TechRepublic消息隊列發送以下對象(列表H)
列表H
[Serializable()]
publicclassMessageContent
{
privateDateTime _creationDate = DateTimeNow;
privatestring _messageText;
public MessageContent()
{
}
public MessageContent(string messageText)
{
_messageText = messageText;
}
publicstring MessageText
{
get { return _messageText; }
set { _messageText = value; }
}
publicDateTime CreationDate
{
get { return _creationDate; }
set { _creationDate = value; }
}
}
給隊列發送這個對象的一個實例只需簡單調用MessageQueueSend方法並把一個對象實例作為參數提交給這個方法列表I說明了這種情況
列表I
MessageContent message = newMessageContent(Hello world!);
queueSend(message Sample Message);
如你所見上面的代碼類似於我們前面發送正文為一個字符串的消息時使用的代碼接收一個包含序列化對象的消息更加困難一些我們需要告訴消息它包含哪種對象
為向消息指出它包含哪種對象我們必須建立消息的格式化器(formatter)給消息的Formatter屬性指定一個SystemMessagingXmlMessageFormatter對象即可建立格式化器由於我們的消息包含一個MessageContent對象我們希望為它配置XmlMessageFormatter
列表J
messageFormatter = new SystemMessagingXmlMessageFormatter(
newType[] { typeof(MessageContent) }
);
既然我們已經給消息指定了一個格式化器我們可以從消息中提取MessageContent對象但在這之前我們需要把messageBody屬性的返回值分配給一個MessageContent對象
列表K
MessageContent content = (MessageContent)messageBody;
在這個例子中content變量是我們向隊列發送的原始MessageContent對象的序列化版本我們可以訪問原始對象的所有屬性和值
設定消息優先級別
在正常情況下隊列中的消息以先進先出的形式被訪問這表示如何你先發送消息A再發送消息B那麼隊列將首先返回消息A然後才是消息B在多數情況下這樣處理沒有問題但是有時由於一條消息比其它消息更加重要你希望將它提到隊列前面要實現這種功能你就需要設定消息優先級別
一條消息的優先級別由它的MessagePriority屬性值決定下面是這個屬性的所有有效值(全部來自MessagePriority的列舉類型)
·最高(Highest)
·非常高(VeryHigh)
·高(High)
·高於正常級別(AboveNormal)
·正常(Normal)
·低(Low)
·非常低(VeryLow)
·最低(Lowest)
消息在隊列中的位置由它的優先級別決定——例如假如隊列中有四條消息兩條消息的優先級別為正常(Normal)另兩條為高(High)則隊列中消息排列如下
·High Priority A——這是發送給隊列的第一條高優先級消息
·High Priority B——這是發送給隊列的第二條高優先級消息
·Normal Priority A——這是發送隊列的第一條正常優先級消息
·Normal Priority B——這是發送隊列的第二條正常優先級消息
根據這個順序如果我們給隊列發送另一條最高優先級的消息它將位於隊列的頂部
如果需要使用消息優先級功能你必須修改發送消息的代碼因為Message對象的構造器沒有指定消息優先級別的功能你必須實例化一個Message對象並在將它發送給隊列之前給它設定相應的屬性列表L中的代碼說明如何設定優先級別並給隊列發送一條最高優先級別的消息
列表L
//Instantiate the queue
MessageQueue queue = newMessageQueue(queueName);
//Create a XmlSerializer for the object type were sending
XmlSerializer serializer = new
XmlSerializer(typeof(MessageContent));
//Instantiate a new message
SystemMessagingMessage queueMessage =
new SystemMessagingMessage();
//Set the priority to Highest
queueMessagePriority = MessagePriorityHighest;
//Create our MessageContent object
MessageContent messageContent =
newMessageContent(Hello world IMPORTANT!);
//Serialize the MessageContent object into the queueMessage
serializerSerialize(queueMessageBodyStream messageContent);
//Send the message
queueSend(queueMessage HIGH PRIORITY);
這段代碼和上面代碼的最明顯區別在於它使用了XmlFormatter它實際是可選的列表L中的代碼也可用列表M中的代碼代替
列表M
//Instantiate a new message
SystemMessagingMessage queueMessage =
new SystemMessagingMessage();
//Set the priority to Highest
queueMessagePriority = MessagePriorityHighest;
//Create our MessageContent object
MessageContent messageContent =
newMessageContent(Hello world IMPORTANT!);
//Set the body as the messageContent object
queueMessageBody = messageContent;
//Send the message
queueSend(queueMessage HIGH PRIORITY);
這段代碼執行和列表L中的代碼相同的任務但代碼更少
應用
輸入消費者請求是MSMQ功能的一個簡單實例消費者提出一個請求由一個面向消費者的應用程序將它送交給消息隊列向隊列發送請求後它會向消費者送出一個確認(acknowledgement)
然後一個獨立的進程從隊列中提取消息並運行任何所需的業務邏輯(business logic)完成業務邏輯後處理系統將向另一個隊列提交一個響應接下來面向消費者的應用程序從隊列中提取這個響應並給消費者返回一個響應
這種類型的配置能夠加快面向消費者的應用程序的速度使其迅速做出反應同時在一個內部系統中完成大量處理工作這樣還可以將請求處理分散到多台內部機器上提供可擴展性
From:http://tw.wingwit.com/Article/program/net/201311/13471.html