MSMQ .NET下的应用
Message
Message是MSMQ的数据存储单元,我们的用户数据一般也被填充在Message的body当中,因此很重要,让我们来看一看其在.net中的体现,如图:
在图上我们可以看见,Message提供了三个构造函数,参数body表示我们的用户数据,当我们在构造函数中传入,数据最终会被赋值给其同名属性body,参数formatter对应同名属性Formatter,它是一个序列化器,当我们的用户数据是一个复杂类型,比如类的时候Message会自动采用该序列化器将我们的复杂类型序列化。message支持3种序列化对象:
-- XMLMessageFormatter对象----MessageQueue组件的默认格式化程序设置。
-- BinaryMessageFormatter对象;
-- ActiveXMessageFormatter对象;
由于后两者格式化后的消息通常不能为人阅读,所以我们经常用到的是XMLMessageFormatter对象。该对象构造方法有三种重载:
public XmlMessageFormatter();
public XmlMessageFormatter(string[] targetTypeNames);
public XmlMessageFormatter(Type[] targetTypes);
MSMQ队列
消息(Message)需要保存在msmq队列中,.net中采用System.Messaging.MessageQueue来管理MSMQ队列,它提供能操作MSMQ的绝大多数API,比如
1.判断指定路径的队列是否存在。其中path代表队列的路径,表示形式为"主机名\队列名称",例如:".\private$\myQueue",其中"."代表本地主机,"\private$\myQueue"则代表队列的名称,"private$"表示我们创建的是专用队列,在网络上我们可以通过路径来唯一确定一个队列。
public static bool Exists(string path);
2.创建队列。path代表队列的路径,transactional表示是否创建事务队列,默认为fasle。关于事务队列我在上一篇做了详细的论述,这里不在重复。
public static MessageQueue Create(string path);
public static MessageQueue Create(string path, bool transactional);
3.删除队列
public static void Delete(string path);
4.发送消息到MSMQ。obj代表我们的用户数据,transation表示将我们的发送操作纳入事务当中。在前面我们说过MSMQ接收的是Message,但是在这里我们看到Send操作并未强制要求我们采用Message类型参数。这是因为当我传入一个Object参数数据时,在Send操作的内部自动的给我们创建了一个Message消息对象,并且将我们的传入的Object参数采用默认的序列化器序列化,然后装入Message的body属性当中,如果我们在Send方法中指定label属性,它将被赋值给Message的同名Label属性。当然我们完全可以自定义一个message对象传入Send方法中
public void Send(object obj);
public void Send(object obj, MessageQueueTransaction transaction);
public void Send(object obj, string label);
5.接收消息。同理接收消息也可以被纳入事务当中,采用Receive方法在取MSMQ的消息时,如果成功,会把MSMQ的对应消息给删除掉,并且只能取到消息队里中的排队头的消息。
public Message Receive();
public Message Receive(MessageQueueTransaction transaction);
public Message Receive(TimeSpan timeout);
如果我们想取指定标识的消息,就的采用如下的方法了,id代表消息的唯一标示。
public Message ReceiveById(string id);
public Message ReceiveById(string id, MessageQueueTransaction transaction);
如果我们在接收消息的后,不想把MSMQ队列中的消息删除怎么办呢?那么采用下面的方法吧,因为这两个方法接收MSMQ的消息,不会删除MSMQ中对应的消息,所以他们不支持事务,即没有提供事务的参数。
public Message Peek();
public Message PeekById(string id);
我们也可以一次性吧队列里面的所有消息取出来
public Message[] GetAllMessages();
实例
说了这么多,下面让我们来代码实战一下,我们采用控制台程序做测试,我把MSMQ队列做了简单的封装,如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Messaging;
using System.Text;
using System.Threading.Tasks; namespace Test
{
public class QueueManger
{
/// <summary>
/// 创建MSMQ队列
/// </summary>
/// <param name="queuePath">队列路径</param>
/// <param name="transactional">是否事务队列</param>
public static void Createqueue(string queuePath, bool transactional = false)
{
try
{
//判断队列是否存在
if (!MessageQueue.Exists(queuePath))
{
MessageQueue.Create(queuePath);
Console.WriteLine(queuePath + "已成功创建!");
}
else
{
Console.WriteLine(queuePath + "已经存在!");
}
}
catch (MessageQueueException e)
{
Console.WriteLine(e.Message);
}
}
/// <summary>
/// 删除队列
/// </summary>
/// <param name="queuePath"></param>
public static void Deletequeue(string queuePath)
{
try
{
//判断队列是否存在
if (MessageQueue.Exists(queuePath))
{
MessageQueue.Delete(@".\private$\myQueue");
Console.WriteLine(queuePath + "已删除!");
}
else
{
Console.WriteLine(queuePath + "不存在!");
}
}
catch (MessageQueueException e)
{
Console.WriteLine(e.Message);
}
}
/// <summary>
/// 发送消息
/// </summary>
/// <typeparam name="T">用户数据类型</typeparam>
/// <param name="target">用户数据</param>
/// <param name="queuePath">队列名称</param>
/// <param name="tran"></param>
/// <returns></returns>
public static bool SendMessage<T>(T target, string queuePath, MessageQueueTransaction tran = null)
{
try
{
//连接到本地的队列
MessageQueue myQueue = new MessageQueue(queuePath);
System.Messaging.Message myMessage = new System.Messaging.Message();
myMessage.Body = target;
myMessage.Formatter = new XmlMessageFormatter(new Type[] { typeof(T) });
//发送消息到队列中
if (tran == null)
{
myQueue.Send(myMessage);
}
else
{
myQueue.Send(myMessage, tran);
}
Console.WriteLine("消息已成功发送到"+queuePath + "队列!");
return true;
}
catch (ArgumentException e)
{
Console.WriteLine(e.Message);
return false;
}
}
/// <summary>
/// 接收消息
/// </summary>
/// <typeparam name="T">用户的数据类型</typeparam>
/// <param name="queuePath">消息路径</param>
/// <returns>用户填充在消息当中的数据</returns>
public static T ReceiveMessage<T>(string queuePath,MessageQueueTransaction tran=null)
{
//连接到本地队列
MessageQueue myQueue = new MessageQueue(queuePath);
myQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(T) });
try
{
//从队列中接收消息
System.Messaging.Message myMessage = tran == null ? myQueue.Receive() : myQueue.Receive(tran);
return (T)myMessage.Body; //获取消息的内容
}
catch (MessageQueueException e)
{
Console.WriteLine(e.Message);
}
catch (InvalidCastException e)
{
Console.WriteLine(e.Message);
}
return default(T);
}
/// <summary>
/// 采用Peek方法接收消息
/// </summary>
/// <typeparam name="T">用户数据类型</typeparam>
/// <param name="queuePath">队列路径</param>
/// <returns>用户数据</returns>
public static T ReceiveMessageByPeek<T>(string queuePath)
{
//连接到本地队列
MessageQueue myQueue = new MessageQueue(queuePath);
myQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(T) });
try
{
//从队列中接收消息
System.Messaging.Message myMessage = myQueue.Peek();
return (T)myMessage.Body; //获取消息的内容
}
catch (MessageQueueException e)
{
Console.WriteLine(e.Message);
}
catch (InvalidCastException e)
{
Console.WriteLine(e.Message);
}
return default(T);
}
/// <summary>
/// 获取队列中的所有消息
/// </summary>
/// <typeparam name="T">用户数据类型</typeparam>
/// <param name="queuePath">队列路径</param>
/// <returns>用户数据集合</returns>
public static List<T> GetAllMessage<T>(string queuePath)
{
MessageQueue myQueue = new MessageQueue(queuePath);
myQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(T) });
try
{
Message[] msgArr= myQueue.GetAllMessages();
List<T> list=new List<T>();
msgArr.ToList().ForEach((o) =>
{
list.Add((T)o.Body);
});
return list;
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
return null;
}
}
}
我们的用户实体也很简单,如下
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks; namespace Test
{
public class Student
{
/// <summary>
/// 年龄
/// </summary>
public int Age { get; set; }
/// <summary>
/// 姓名
/// </summary>
public string Name { get; set; }
}
}
下面我们来创建一个队列,如图我们成功的创建了"myqueue"队列
using System;
using System.Collections.Generic;
using System.Linq;
using System.Messaging;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
static void Main(string[] args)
{
string queuepath = @".\private$\myQueue";
QueueManger.Createqueue(queuepath);
Console.ReadKey();
}
}
}
下面我们向队列中发送消息。如图,从图右边可以看到消息成功被加入到队列中
using System;
using System.Collections.Generic;
using System.Linq;
using System.Messaging;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
static void Main(string[] args)
{
string queuepath = @".\private$\myQueue";
//QueueManger.Createqueue(queuepath);
Student stu = new Student() { Name="shaoshun",Age=};
QueueManger.SendMessage<Student>(stu, queuepath);
Console.ReadKey();
}
}
}
接着我们采用Peek方法接收消息(即不移除MSMQ的对应消息),很显然图中的Message依然存在MSMQ队列中
using System;
using System.Collections.Generic;
using System.Linq;
using System.Messaging;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
static void Main(string[] args)
{
string queuepath = @".\private$\myQueue";
//QueueManger.Createqueue(queuepath);
//Student stu = new Student() { Name="shaoshun",Age=18};
//QueueManger.SendMessage<Student>(stu, queuepath);
Student stu= QueueManger.ReceiveMessageByPeek<Student>(queuepath);
Console.WriteLine(stu.Name);
Console.ReadKey();
}
}
}
接着我们采用Receive方法来接收消息。这个时候我们可以很明显的看见MSMQ原来对应的消息被删除了
using System;
using System.Collections.Generic;
using System.Linq;
using System.Messaging;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
static void Main(string[] args)
{
string queuepath = @".\private$\myQueue";
//QueueManger.Createqueue(queuepath);
//Student stu = new Student() { Name="shaoshun",Age=18};
//QueueManger.SendMessage<Student>(stu, queuepath);
//Student stu= QueueManger.ReceiveMessageByPeek<Student>(queuepath);
Student stu = QueueManger.ReceiveMessage<Student>(queuepath);
Console.WriteLine(stu.Name);
Console.ReadKey();
}
}
}
最后让我来测试,MSMQ的事务性。我们先删除我们的队列,在重新创建。我们连续向队列中插入5个消息,但是在插入第5个消息的时候我们抛出异常,如果MSMQ支持事务的话那么前面发送的4个Message将被回滚掉,MSMQ队列中应该为0个消息
using System;
using System.Collections.Generic;
using System.Linq;
using System.Messaging;
using System.Text;
using System.Threading.Tasks; namespace Test
{
class Program
{
static void Main(string[] args)
{
string queuepath = @".\private$\myQueue";
//QueueManger.Createqueue(queuepath);
//Student stu = new Student() { Name="shaoshun",Age=18};
//QueueManger.SendMessage<Student>(stu, queuepath);
//Student stu= QueueManger.ReceiveMessageByPeek<Student>(queuepath);
//Student stu = QueueManger.ReceiveMessage<Student>(queuepath);
//Console.WriteLine(stu.Name); QueueManger.Deletequeue(queuepath);
QueueManger.Createqueue(queuepath);
MessageQueueTransaction tran = new MessageQueueTransaction();
tran.Begin();
try
{
Student stu;
for (int i = ; i < ; i++)
{
stu=new Student(){Name="shaoshun"+i,Age=i};
QueueManger.SendMessage<Student>(stu, queuepath, tran);
if (i == )
{
throw new Exception();
}
}
tran.Commit();
}
catch
{
tran.Abort();
}
Console.ReadKey();
}
}
}
另外值得注意的是,MSMQ的消息发送与接收,采用的是同步的方式。这样假如我们的消息队列中一个消息都没有,我们调用Receive()去接收该队列的消息会怎么样呢? 程序会被阻塞在这里,直到消息队列中有消息,程序才会接着往下走。碰到这种情况是很要命的,但是不怕MSMQ支持异步消息,由于篇幅有限我就不在多少,这里我给出一个异步操作的链接有兴趣的朋友可以去研究下,
MSMQ .NET下的应用的更多相关文章
- 分布式消息总线,基于.NET Socket Tcp的发布-订阅框架之离线支持,附代码下载
一.分布式消息总线以及基于Socket的实现 在前面的分享一个分布式消息总线,基于.NET Socket Tcp的发布-订阅框架,附代码下载一文之中给大家分享和介绍了一个极其简单也非常容易上的基于.N ...
- WCF全面解析学习(1)
SOA的基本概念和设计思想 SOA并不是仅仅采用Web服务的架构,Web服务只是一种实现SOA的理想技术手段.SOA依赖于开放的标准.SOA的一个目标是让不同的厂商开发的服务能够相互操作. SOA支持 ...
- C++程序结构---1
C++ 基础教程Beta 版 原作:Juan Soulié 翻译:Jing Xu (aqua) 英文原版 本教程根据Juan Soulie的英文版C++教程翻译并改编. 本版为最新校对版,尚未定稿.如 ...
- .Net下的MSMQ(微软消息队列)的同步异步调用
一.MSMQ简介 MSMQ(微软消息队列)是Windows操作系统中消息应用程序的基础,是用于创建分布式.松散连接的消息通讯应用程序的开发工具.消息队列 和电子邮件有着很多相似处,他们都包含多个属性, ...
- .NET分布式事务处理总结【下】 - 包含MSMQ的分布式事务处理
转自:http://www.cnblogs.com/daxnet/archive/2011/03/15/1984995.html .NET直接提供对MSMQ的访问支持,只需要添加System.Mess ...
- Delphi下MSMQ(Mircosoft Message Queue)实例(私有队列)
网上关于消息队列技术原理说明的详细文档很多,但涉及到Delphi的具体实现很少,这是我从网上找了一上午的资料,自己整合和尝试的能运行的程序. 打开控制面板->程序->添加组件,添加消息队列 ...
- 已经过事务处理的 MSMQ 绑定(转载)
https://msdn.microsoft.com/zh-cn/biztalk/ms751493 本示例演示如何使用消息队列 (MSMQ) 执行已经过事务处理的排队通信. 注意 本主题的末尾介绍了此 ...
- 基于WCF MSMQ 的企业应用解决方案
最近研究了一下基于MSMQ的WCF应用,从书上.网上查了很多资料,但始终没能彻底理解WCF-MSMQ的工作原理,也没能得到一个合理的应用解决方案.索性还是自己做个实验,探索一下吧.经过反复试验,颇有收 ...
- Redis学习笔记~实现消息队列比MSMQ更方便
什么是队列:简单的说就是数据存储到一个空间里(可以是内存,也可以是物理文件),先存储的数据对象,先被取出来,这与堆栈正好相反,消息队列也是这样,将可能出现高并发的数据进行队列存储,并按着入队的顺序依次 ...
随机推荐
- [server]阿里云服务器远程文件传输的解决方案
在今年6月份以前使用windows自带的远程桌面还可以畅快无阻地进行稍大文件的传输.但是后来就总是会蹦了.最近频繁使用,发现已经不能愉快地的传输文件了,就是挂载本地驱动器,只能传输很小,大概小于40M ...
- java 两行代码解析json文件
public void JsonRead() throws IOException{ String str = FileUtils.readFileToString(new File("D: ...
- ios中iframe页面出现白屏问题
最近用ionic3开发的一个项目在ios中出现了白屏的问题 banner轮播图跳转网页 使用了iframe 但是却时不时的出现白屏现象 在android中一切正常 网上查资料发现 是因为ios不允许访 ...
- jQuery常用 遍历函数
jQuery 遍历函数包括了用于筛选.查找和串联元素的方法.本文主要介绍日常工作中常用的JQ遍历,帮助一下初学者快速的接触遍历函数,提高自己的代码编写速度,写出更简洁更实用的代码,祝前端的同学们,在前 ...
- WEB 设计规范
WEB端设计规范 一.网页尺寸 一般网站宽为996px:国内网站大部分还是以1000个像素为界限,因超过1000像素适合在大屏幕上浏览,小屏幕会显得拥挤.国内尺寸设置比较保守,这样可以保证 ...
- Oracle中计算两个日期时间的差
--方法1 select floor((sysdate - to_date('2006-09-01 08:00:00', 'yyyy-mm-dd hh24:mi:ss'))) as sDays fro ...
- Python_文件处理
1.Python 文件处理 打开文件---->读取内容---->获得内容 读取文件方式: r 只读文件 w 只写模式 a 追加模式 r+b 读写模式 w+b 写读模式 a+b ...
- iOS证书申请及使用详细说明
iOS 证书申请和使用详解(详细版)阅读 对于iOS开发者来说,apple开发者账号肯定不会陌生.在开发中我们离不开它.下面我简单的为大家分享一下关于iOS开发中所用的证书相关知识. 第一部分:成 ...
- 小学生噩梦——四则运算题库(python 全功能实现)
Github: https://github.com/holidaysss 小组:龙天尧(代码实现),林毓植(浮点转分数函数,代码审查) PSP2.1 Personal Software Proces ...
- django学习:一些疑惑
昨天学习了django的第二天,有一些收获. django的语法很严谨,看上去明明对齐的,但是他却提示说缩进不一致.后来我把前面的空全部删除,全部采用空格,这样就通过了,看样子还是要编程有一个好习惯, ...