MSMQ消息通知系统之消息队列创建、发送、接收
--背景
1.消息通知系统。
2.在进行系统设计时,除了对安全、事务等问题给与足够的重视外,性能也是一个不可避免的问题所在,尤其是一个B/S结构的软件系统,必须充分地考虑访问量、数据流量、服务器负荷的问题。解决性能的瓶颈,除了对硬件系统进行升级外,软件设计的合理性尤为重要。对于一些实时性不是很高的模块我们可以使用了Microsoft
Messaging Queue(MSMQ)技术来完成异步处理,利用消息队列临时存放要操作的数据,使得数据访问因为不需要访问数据库从而提高了访问性能,至于队列中的数据,则等待系统空闲的时候再进行处理。[部分语言来自张逸blog: http://www.cnblogs.com/wayfarer/]
3.消息通知系统就是利用MSMQ技术、window服务实现一系列的通知服务
--结构图
--消息队列的安装
关于消息队列的基本知识,我在这里就不多说了。大家可以看看下面的资料
http://www.cnblogs.com/rickie/archive/2004/11/16/64345.html
http://www.microsoft.com/china/msdn/events/webcasts/shared/webcast/consyscourse/ASPNETpractise.aspx
http://www.cnblogs.com/rickie/archive/2004/11/17/64712.html
http://www.cnblogs.com/wayfarer/archive/2007/03/15/496207.html
1:安装消息队列window组件,建立事务性专用队列[private$\]
a.通过控制面板,”添加删除程序”->”添加/删除window组件”->安装MSMQ
b.配置MSMQ:计算机管理-消息队列。在专有队列下创建指定的事务性队列.[
MsmsqQueue]
2: 可以使用installutil.exe安装编译后的exe 的windows服务
--消息体
消息是两台计算机间传送的数据单位,消息可以非常简单,例如只包含文本字符串;也可以很复杂,可能包含嵌入对象。
在进行消息操作前,我们先定义一个超类[SuperClass].以作为消息通知系统的消息体。
代码如下:
using System;
using System.Collections.Generic;
using System.Text;
namespace
MsMqDemo
{
[Serializable]
public class MessageBase
{
/// <summary>
/// 消息类型
/// </summary>
private
string messagetype;
public string MessageType
{
get
{ return messagetype; }
set
{ messagetype = value; }
}
/// <summary>
/// 消息内容
/// </summary>
private
string messagebody;
public string MessageBody
{
get
{ return messagebody; }
set
{ messagebody = value; }
}
}
}
--消息的发送、接受
上面结构图的MsgRecorder就是消息的发送、接收器
在这个消息通知系统,我们可以借鉴Petshop4.0的消息处理的方式作为我们的MsgRecorder.
1> 消息接口IMessaging
using System;
using System.Collections.Generic;
using System.Text;
namespace MsMqDemo
{
public interface IRecorder
{
/// <summary>
/// Method to send an order to a message queue for later
processing
/// </summary>
/// <param
name="body">All information about
an order</param>
void
Send(MessageBase msg);
MessageBase
Receive();
MessageBase
Receive(int timeout);
}
}
2> PetShopQueue
using System;
using System.Messaging;
namespace MsmqDemo
{
/// <summary>
/// This could be a base class for all PetShop MSMQ messaging
implementation as
/// it provides a basic implementation for sending and
receving messages to and from transactional queue
/// </summary>
public class PetShopQueue
: IDisposable {
protected
MessageQueueTransactionType transactionType
= MessageQueueTransactionType.Automatic;
protected
MessageQueue queue;
protected
TimeSpan timeout;
public
PetShopQueue(string queuePath, int timeoutSeconds) {
queue = new
MessageQueue(queuePath);
timeout = TimeSpan.FromSeconds(Convert.ToDouble(timeoutSeconds));
//
Performance optimization since we don't need these features
queue.DefaultPropertiesToSend.AttachSenderId = false;
queue.DefaultPropertiesToSend.UseAuthentication = false;
queue.DefaultPropertiesToSend.UseEncryption = false;
queue.DefaultPropertiesToSend.AcknowledgeType
= AcknowledgeTypes.None;
queue.DefaultPropertiesToSend.UseJournalQueue = false;
}
/// <summary>
/// Derived classes may call this from their own Send methods
that
/// accept meaningful objects.
/// </summary>
public virtual void Send(object msg) {
queue.Send(msg, transactionType);
}
public virtual object
Receive()
{
try
{
using
(Message message = queue.Receive(timeout,
transactionType))
return
message;
}
catch
(MessageQueueException mqex)
{
if
(mqex.MessageQueueErrorCode == MessageQueueErrorCode.IOTimeout)
throw
new TimeoutException();
throw;
}
}
#region IDisposable Members
public void Dispose() {
queue.Dispose();
}
#endregion
}
}
3>MessageRecorder
using System;
using System.Configuration;
using System.Messaging;
namespace MsmqDemo
{
/// <summary>
/// This class is an implementation for sending and receiving
orders to and from MSMQ
/// </summary>
public class MsgRecorder
: PetShopQueue, IRecorder
{
// Path
example - FormatName:DIRECT=OS:MyMachineName\Private$\OrderQueueName
private
static readonly
string queuePath = ConfigurationManager.AppSettings["MessageQueuePath"];
private
static int
queueTimeout = 20;
public
MsgRecorder() : base(queuePath, queueTimeout)
{
Type[]
t = new Type[]
{typeof(MessageBase)
};
queue.Formatter = new XmlMessageFormatter(t);
}
/// <summary>
/// Method to retrieve
MessageBase from Message Queue
/// </summary>
/// <returns>All information for an MessageBase</returns>
public new MessageBase
Receive()
{
// This
method involves in distributed transaction and need Automatic Transaction type
base.transactionType
= MessageQueueTransactionType.Automatic;
return
(MessageBase)((Message)base.Receive()).Body;
}
public MessageBase Receive(int
timeout)
{
base.timeout
= TimeSpan.FromSeconds(Convert.ToDouble(timeout));
return
Receive();//base.Receive();base.timeout
}
/// <summary>
/// Method to send asynchronous order to Message Queue
/// </summary>
/// <param
name="orderMessage">All information
for an MessageBase</param>
public void Send(MessageBase
msg)
{
// This
method does not involve in distributed transaction and optimizes performance
using Single type
base.transactionType
= MessageQueueTransactionType.Single;
base.Send(msg);
}
}
}
>4 工厂
using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using System.Configuration;
using System.Messaging;
namespace MsmqDemo
{
public sealed class DataAccess
{
private
static readonly
string recorderPath = ConfigurationManager.AppSettings["RecorderDAL"];
/// <summary>
/// 创建记录器
/// </summary>
/// <returns></returns>
public static IRecorder CreateRecorder()
{
string
className = recorderPath + ".MsgRecorder";
return
(IRecorder)Assembly.Load(recorderPath).CreateInstance(className);
}
消息的发送、接受器的代码已经贴完,先写到这里,待续。。。