public static T GetMessage<T>(string path, bool isDeleteMessage = true, bool transactional = false)
{
T result = default(T);
try
{
using (MessageQueue mqReceiver = new MessageQueue(path))
{
mqReceiver.MessageReadPropertyFilter.Body = true;
mqReceiver.MessageReadPropertyFilter.AppSpecific = true;
mqReceiver.MessageReadPropertyFilter.Priority = true;
mqReceiver.MessageReadPropertyFilter.Recoverable = true; // 防止重启主机时丢失消息
mqReceiver.Formatter = new XmlMessageFormatter(new Type[] { typeof(T) });
Message message = null;
if ( transactional == true)
{
if (isDeleteMessage == true)
{
using (MessageQueueTransaction tran = new MessageQueueTransaction())
{
tran.Begin();
Console.WriteLine("等待接收......");
message = mqReceiver.Receive(tran);
Console.WriteLine("接到了");
tran.Commit();
}
}
else
message = mqReceiver.Peek();
}
else
{
if (isDeleteMessage)
{
Console.WriteLine("等待接收......");
message = mqReceiver.Receive();
Console.WriteLine("接到了");
}
else
message = mqReceiver.Peek();
}
if (message != null)
result = (T)message.Body;
mqReceiver.Close();
}
}
catch (MessageQueueException ex)
{
Console.Write(ex);
}
catch (Exception ex)
{
Console.Write(ex);
}
return result;
}
申:
以下代码在调试远端的主机时会出现异常
bool b = MessageQueue.Exists(path); // 按说应该不会,但是我的机器调试时总出错,不知道为什么?
MessageQuene m = MessageQuene.Create(path);// 不知道,反正没有通过
bool b = m.Transactional; // 好像在远端时不支持这个属性了
以上信息在本地时没有任何问题,O(∩_∩)O~
一点补充:
以下只在本地有效,不知道远端是否有效,没试过
如何得到本地的私有队列中的消息的数量(主要代码如下:)
using System.Diagnostics;
return (long)(new PerformanceCounter("MSMQ Queue", "Messages in Queue", path).NextValue());
如果在执行以上代码时出现注册表缺少什么等等的 InvalidOperationException 时,请以管理员的方式在 DOS 中执行
命令 "lodctr /R",也可以通过命令 "perfmon" 查看性能计数器的情况
另外说明在 path 中本地机器名要给全例如 @"MyPC\Private$\MyPath",不能用省略符号 @".\Private$\MyPath"替代
在进行MSMQ的编程时,请添加引用 System.Message.dll 并添加对应的命名空间的引用
其实除了 MSMQ ,我们还是有很多其他的选择的,例如 ActiveMQ 等等,有兴趣大家可以看看了......
关于在集群中使用队列
1、要在集群中使用队列,请在集群中的每个主机的私有队列中创建自己的队列(最好创建事务性队列),例如我的集群中包含两台主机 192.168.117.47、192.168.117.48,共同的漂移地址是192.168.117.50,那我就在每台主机的 MSMQ 的私有队列中分别创建 \private$\MyPath (创建时指定带有事务)
2、在创建队列之后,请在队列的属性中指定用户及该用户对队列的访问权限,否则访问队列的客户端程序将不能正确的发送和接收队列。
3、发送消息时,要使用漂移地址 192.168.117.50 发送,同时指定发送消息时要启用事务
4、接收消息时,请使用单机的 IP 192.168.117.47 或 192.168.117.48 接收队列,同时,请不要指定接收消息的队列启用事务,嘿嘿,这里是不是和不在集群时的情况有些不同,同时也和发送消息有些不一样呢?!
5、之前给出的代码是采用的格式化是 XmlMessageFormatter,这就要求在接收消息时必须要知道消息中对象的类型,如果我们在发送和接收消息时指定 MessageQueue.Formatter = new BinaryMessageFormatter(),则可以在发送和接收消息时不用知道消息中包含的对象的类型了
之前的接收都是同步接收消息,有没有办法来异步获取消息呢?当然可以,代码如下:
主调方代码:
MessageQueue mq = GetMessageQueue(path); // GetMessageQueue 函数如何实现就不写了吧?!
mq.ReceiveCompleted += new ReceiveCompletedEventHandler(mq_ReceiveCompleted);
mq.BeginReceive();
回调函数
private void mq_ReceiveCompleted(object sender, ReceiveCompletedEventArgs e)
{
MessageQueue mq = sender as MessageQueue;
if (mq != null && e != null)
{
Message message = mq.EndReceive(e.AsyncResult);
if (message != null)
Console.WriteLine(message.Body);
mq.BeginReceive();
}
}
这是接收消息之后就删除的代码,当然也可以做接收消息但不删除的,这里就不再熬诉了