--背景
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);
}
消息的发送、接受器的代码已经贴完,先写到这里,待续。。。