访问传出消息队列 (MSMQ)






3.75/5 (7投票s)
一篇描述如何访问发件箱消息队列的文章。
引言
本文描述了如何访问发件箱消息队列,以及如何从发件箱队列中查看和接收消息。
背景
有人要求我开发一个模块,用户可以在其中查看未送达的消息,即那些应该发送给客户端但由于客户端不可用(客户端机器在网络中不可用)而被发送到发件箱队列的消息(这是 Microsoft 消息队列的默认行为)。
起初,我以为这会是一个简单的任务,但在做了一些研究后,我发现它不会像我预想的那么容易。但不知何故,我设法找到了关于如何执行此操作的参考资料。
还有一些事情我仍然无法做到,例如,我仍然无法删除/清除发件箱队列中的消息。我仍然无法获取原始的发件箱队列名称 - 我现在通过选择本地系统中的所有活动队列并过滤掉名称中包含 "private" 的队列来完成此操作,因为发件箱队列始终在其名称中包含 "Direct"。
我承认代码有点粗糙,因为这只是一个快速尝试提交我的第一篇文章。希望它对我的 C# 开发者同伴有所帮助。
使用代码
本文中的代码基于 COM MSMQ 库。您必须从“添加引用”窗口的“COM”选项卡中添加对 Microsoft Message Queue 3.0 Object 库的引用,如下图所示。
以下代码将返回 ArrayList
中的所有发件箱队列名称。正如我之前所说,我仍然无法获取真正的发件箱队列。在这里,我假设在所有活动队列中,名称中包含“Direct=”的队列是发件箱队列。
此方法使用 MSMQ.MSMQApplication
COM 对象来获取所有活动队列的名称; 从这些名称中,我们过滤掉名称中包含 "Direct=" 的队列作为我们所需的队列。 关于 MSMQ.MSMQApplication
类的更多信息,请参阅 此处。
private ArrayList GetOutGoingQueueName()
{
ArrayList OutgoingQueuename = new ArrayList();
try
{
MSMQ.MSMQApplication q = new MSMQ.MSMQApplication();
object obj = q.ActiveQueues;
Object[] oArray = (Object[])obj;
for (int i = 0; i < oArray.Length; i++)
{
if (oArray[i] == null)
continue;
if (oArray[i].ToString().IndexOf("DIRECT=") >= 0)
{
OutgoingQueuename.Add(oArray[i].ToString());
}
}
}
catch (Exception ee)
{
MessageBox.Show(ee.ToString());
}
return OutgoingQueuename;
}
下一个方法将返回队列中的消息总数,当队列名称作为方法参数提供时。
此方法使用 MSMQ.MSMQManagement
对象来初始化队列。 在调用 Init
方法后,对象 mgmt
被转换为 MSMQ.MSMQOutgoingQueueManagement
对象,以获取发件箱消息队列中的消息计数。 关于 MSMQ.MSMQManagement
和 MSMQ.MSMQOutgoingQueueManagement
的更多信息,请分别参阅 此处 和 此处。
private int GetMessageCount(string queueName)
{
int count = 0;
try
{
MSMQ.MSMQManagement mgmt = new MSMQ.MSMQManagement();
MSMQ.MSMQOutgoingQueueManagement outgoing;
String s = "YOURPCNAME";
Object ss = (Object)s;
String pathName = queueName;
Object pn = (Object)pathName;
String format = null;
Object f = (Object)format;
mgmt.Init(ref ss , ref f, ref pn);
outgoing = (MSMQ.MSMQOutgoingQueueManagement)mgmt;
count = outgoing.MessageCount;
}
catch (Exception ee)
{
MessageBox.Show(ee.ToString());
}
return count;
}
第三个方法“ReceiveMessage
”将从队列中返回消息,其名称在参数列表中提供。 另一个参数定义要从队列中读取的消息数量。 以下方法使用 MSMQ.MSMQQueueInfo
类读取发件箱队列中的消息。 MSMQQueueInfo
类的 Open
方法需要两个参数。 第一个参数指定应用程序如何访问队列,第二个参数指定谁可以访问队列。 关于这些参数的更多信息,请参阅 此处。
Open
方法将返回一个 MSMQ.MSMQQueue
类对象,您可以使用该对象从消息队列接收或查看消息。
关于 MSMQQueueInfo
、MSMQQueue
和 MSMQMessage
的更多信息,请分别参阅 此处、此处 和 此处。
private ArrayList ReceiveMessage(string queueFormatName, int numOfMessagesToRead)
{
ArrayList messages = new ArrayList();
try
{
MSMQ.MSMQQueueInfo info = new MSMQ.MSMQQueueInfo();
info.FormatName = queueFormatName;
MSMQ.MSMQQueue mq = info.Open((int)(MSMQ.MQACCESS.MQ_ADMIN_ACCESS |
MSMQ.MQACCESS.MQ_RECEIVE_ACCESS), (int)MSMQ.MQSHARE.MQ_DENY_NONE);
object wantdest = false;
object tr = true;
object num = 0;
for (int i = 0; i < numOfMessagesToRead; i++)
{
MSMQ.MSMQMessage msg = mq.ReceiveCurrent(ref wantdest,
ref wantdest, ref tr, ref num, ref wantdest);
if (msg == null)
continue;
messages.Add(System.Text.ASCIIEncoding.ASCII.GetString((byte[])msg.Body));
}
}
catch (Exception ee)
{
MessageBox.Show(ee.ToString());
}
return messages;
}
Peek
和 Receive
之间的主要区别在于,Peek
方法仅读取消息,而不将其从队列中删除,而 Receive
方法在读取消息后将其从队列中删除。
private ArrayList PeekMessage(string queueFormatName, int numOfMessagesToRead)
{
ArrayList messages = new ArrayList();
try
{
for (int i = 0; i < numOfMessagesToRead; i++)
{
MSMQ.MSMQQueueInfo info = new MSMQ.MSMQQueueInfo();
info.FormatName = queueFormatName;
MSMQ.MSMQQueue mq = info.Open((int)(MSMQ.MQACCESS.MQ_ADMIN_ACCESS |
MSMQ.MQACCESS.MQ_PEEK_ACCESS), (int)MSMQ.MQSHARE.MQ_DENY_NONE);
object wantdest = false;
object tr = true;
object num = 0;
MSMQ.MSMQMessage msg = null;
if (i == 0)
msg = mq.PeekCurrent(ref wantdest, ref tr, ref num, ref wantdest);
else
msg = mq.PeekNext(ref wantdest, ref tr, ref num, ref wantdest);
if (msg == null)
continue;
XmlDocument doc = new XmlDocument();
doc.LoadXml(System.Text.ASCIIEncoding.ASCII.GetString((byte[])msg.Body));
XmlNode NODE = doc.SelectSingleNode("descendant::string");
messages.Add(NODE.InnerText);
}
}
catch (Exception ee)
{
MessageBox.Show(ee.ToString());
}
return messages;
}
历史
- 2008 年 1 月 11 日 - 文章发布。
- 2008 年 1 月 15 日 - 首次更新 -
PeekMessage()
方法实现已更改,并且文章格式已更改。