MSMQ JSON message formatter
Use JSON to serialize and deserialize message queue messages
Storing objects in the message queue (MSMQ) is based on the serialization of the object instance using some of the serializes, basically any class the implements IMessageFormatter. Most commonly used ones are BinaryMessageFormatter and XmlMessageFormatter.
I prefer XmlMessageFormatter over BinaryMessageFormatter, mostly because messages are stored in a readable format inside the queue, so in case something goes wrong you can direly check the content of the message using built Computer Management MMC (Microsoft management console) in the.
Not so nice thing with storing messages in XML is that it is not so small format for storing. Logically, it is a lot better to use JSON but since there is not out of the box class in .NET framework, people still decide to use XmlMessageFormatter. Luckily, since formatter of the MessageQueue object can be any class which implements IMessageFormatter, it is quite easy to write new message formatter for the MessageQueue class.
using NetJSON; using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Messaging; using System.Text; using System.Threading.Tasks; namespace MessageQueuing { public class JsonMessageFormatter<T> : IMessageFormatter { private Encoding encoding; public JsonMessageFormatter() { this.encoding = Encoding.UTF8; } public JsonMessageFormatter(Encoding encoding) { this.encoding = encoding; } public bool CanRead(Message message) { if (message == null) { throw new ArgumentNullException("message"); } var stream = message.BodyStream; return stream != null && stream.CanRead && stream.Length > 0; } public object Clone() { return new JsonMessageFormatter<T>(encoding); } public object Read(Message message) { if (message == null) { throw new ArgumentNullException("message"); } using (var reader = new StreamReader(message.BodyStream, encoding)) { var json = reader.ReadToEnd(); return NetJSON.NetJSON.Deserialize<T>(json); } } public void Write(Message message, object obj) { if (message == null) { throw new ArgumentNullException("message"); } string json = NetJSON.NetJSON.Serialize(obj); message.BodyStream = new MemoryStream(encoding.GetBytes(json)); } } }
The size of the messages
As I mentioned, the main advantage of this format for storing messages in MSMQ is size. To prove this, I used the following sample class as a message and add it to queue using both Json and Xml message formatters.
namespace MessageQueuing.TestApplication { public class SampleModel { public string ID { get; set; } public DateTime TimeCreated { get; set; } } }
For storing and reading the messages I used MessageQueueManager library which wraps build in MSMQ .NET classes for easier usage.
/* Using JSON formatter */ using (var queueManager = new MessageQueueManager<SampleModel>(@".\private$\TestQueue", new JsonMessageFormatter())) { queueManager.AddMessage(new SampleModel() { ID = Guid.NewGuid().ToString(), TimeCreated = DateTime.Now }); } /* Using XML formatter */ using (var queueManager = new MessageQueueManager<SampleModel>(@".\private$\TestQueue", new XmlMessageFormatter())) { queueManager.AddMessage(new SampleModel() { ID = Guid.NewGuid().ToString(), TimeCreated = DateTime.Now }); }
This sample code will put two messages of the same type to message queue and you can see the obvious difference in size.
However, both of the messages are still readable and you can still check the content of them from the MMC.
The speed
The main focus of JsonMessageFormatter is to reduce the size, but apparently the speed is also improved with the new formatter. Again, to cut the story, the following is a simple test which uses same POCO class from the size test.
var JsonTimer = Stopwatch.StartNew(); new JsonMessageFormatter().Write(new Message(), new SampleModel()); JsonTimer.Stop(); var XmlTimer = Stopwatch.StartNew(); new XmlMessageFormatter().Write(new Message(), new SampleModel()); XmlTimer.Stop(); Console.WriteLine("JSON: {0}", JsonTimer.ElapsedMilliseconds); Console.WriteLine("XML: {0}", XmlTimer.ElapsedMilliseconds);
Result is the following:
As you can see, there is no huge gap in the speed, but still few millisecond during a large traffic volume can make a big difference sometime.
References
Disclaimer
Purpose of the code contained in snippets or available for download in this article is solely for learning and demo purposes. Author will not be held responsible for any failure or damages caused due to any other usage.
Comments for this article