在使用MSMQ的時候一般只會使用默認的XML序列化來對消息進行存儲,但XML存儲的缺點是序列化體積相對比較大和效率上有點低.其實.net提供非常簡單的方式讓我們實現不同序列化方式來存儲MSMQ信息,如json,protobuf等.為了能夠讓開發人員實現自定義序列化的消息存儲,.NET提供了IMessageFormatter這樣一個接口,只需要簡單地實現這個接口就可以對MSMQ的消息進行處理.以下講解如何實現json和protobuf的messageformater.
IMessageFormatter
// 摘要:
// 從“消息隊列”消息體序列化或反序列化對象。
[TypeConverter(typeof(MessageFormatterConverter))]
public interface IMessageFormatter : ICloneable
{
// 摘要:
// 在類中實現時,確定格式化程序是否可以反序列化消息的內容。
//
// 參數:
// message:
// 要檢查的 System.Messaging.Message。
//
// 返回結果:
// 如果格式化程序可以反序列化消息,則為 true;否則為 false。
bool CanRead(Message message);
//
// 摘要:
// 在類中實現時,讀取給定消息中的內容並創建包含該消息中的數據的對象。
//
// 參數:
// message:
// The System.Messaging.Message to deserialize.
//
// 返回結果:
// 反序列化的消息。
object Read(Message message);
//
// 摘要:
// 在類中實現時,將對象序列化到消息體中。
//
// 參數:
// message:
// System.Messaging.Message,它將包含序列化的對象。
//
// obj:
// 要序列化到消息中的對象。
void Write(Message message, object obj);
}
接口非常簡單,主要規范了MSMQ寫入和讀取的規則.
Json Formater
public class JsonFormater<T> : IMessageFormatter
{
public bool CanRead(Message message)
{
return message.BodyStream != null && message.BodyStream.Length > 0;
}
[ThreadStatic]
private static byte[] mBuffer;
public object Read(Message message)
{
if(mBuffer== null)
mBuffer = new byte[4096];
int count =(int)message.BodyStream.Length;
message.BodyStream.Read(mBuffer, 0, count);
return Newtonsoft.Json.JsonConvert.DeserializeObject(Encoding.UTF8.GetString(mBuffer, 0, count), typeof(T));
}
[System.ThreadStatic]
private static System.IO.MemoryStream mStream;
public void Write(Message message, object obj)
{
if (mStream == null)
mStream = new System.IO.MemoryStream(4096);
mStream.Position = 0;
mStream.SetLength(4095);
string value = Newtonsoft.Json.JsonConvert.SerializeObject(obj);
int count = Encoding.UTF8.GetBytes(value, 0, value.Length, mStream.GetBuffer(), 0);
mStream.SetLength(count);
message.BodyStream = mStream;
}
public object Clone()
{
return this;
}
}
Protobuf Formater
public class ProtobufFormater<T> : IMessageFormatter
{
public bool CanRead(Message message)
{
return message.BodyStream != null && message.BodyStream.Length > 0;
}
public object Read(Message message)
{
return ProtoBuf.Meta.RuntimeTypeModel.Default.Deserialize(message.BodyStream, null, typeof(T));
}
[System.ThreadStatic]
private static System.IO.MemoryStream mStream ;
public void Write(Message message, object obj)
{
if (mStream == null)
mStream = new System.IO.MemoryStream(4096);
mStream.Position = 0;
mStream.SetLength(0);
ProtoBuf.Meta.RuntimeTypeModel.Default.Serialize(mStream, obj);
message.BodyStream = mStream;
}
public object Clone()
{
return this;
}
}
使用Formater
使有自定義Formater比較簡單,只需要指定MessageQueue的Formatter屬性即可.
MessageQueue queue = new MessageQueue(@".\private$\Test");
queue.Formatter = new JsonFormater<User>();
簡單的測性能測試
針對json,protobuf這兩種自定義序列化和默認的XML序列化性能上有多大差異,各自進行100000條寫入和讀取的耗時情況.
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
sw.Reset();
sw.Start();
for (int i = 0; i < 100000; i++)
{
queue.Send(user);
}
sw.Stop();
Console.WriteLine("MSMQ send xml formater:" + sw.Elapsed.TotalMilliseconds + "ms");
sw.Reset();
sw.Start();
for (int i = 0; i < 100000; i++)
{
User result = (User)queue.Receive().Body;
}
sw.Stop();
Console.WriteLine("MSMQ receive xml formater:" + sw.Elapsed.TotalMilliseconds + "ms");
queue.Formatter = new JsonFormater<User>();
sw.Reset();
sw.Start();
for (int i = 0; i < 100000; i++)
{
queue.Send(user);
}
sw.Stop();
Console.WriteLine("MSMQ send Json formater:" + sw.Elapsed.TotalMilliseconds + "ms");
sw.Reset();
sw.Start();
for (int i = 0; i < 100000; i++)
{
User result = (User)queue.Receive().Body;
}
sw.Stop();
Console.WriteLine("MSMQ receive json formater:" + sw.Elapsed.TotalMilliseconds + "ms");
queue.Formatter = new ProtobufFormater<User>();
sw.Reset();
sw.Start();
for (int i = 0; i < 100000; i++)
{
queue.Send(user);
}
sw.Stop();
Console.WriteLine("MSMQ send Protobuf formater:" + sw.Elapsed.TotalMilliseconds+"ms");
sw.Reset();
sw.Start();
for (int i = 0; i < 100000; i++)
{
User result = (User)queue.Receive().Body;
}
sw.Stop();
Console.WriteLine("MSMQ receive Protobuf formater:" + sw.Elapsed.TotalMilliseconds + "ms");
測試結果

從測試來看還是protobuf效率上占優點:)
