Thirteen Days a Week

  Home  |   Contact  |   Syndication    |   Login
  23 Posts | 0 Stories | 15 Comments | 0 Trackbacks

News

Archives

Post Categories

Thursday, August 05, 2010 #

Yesterday I was asked to help out on another project that was trying to read some messages from an MQSeries queue.  For this particular project, they were using C# and the MQ API rather than BizTalk, because they were dealing with “grouped” messages.  Grouped messages were a completely new concept to me.  Basically, the gist of it is that you have 1 – N physical messages that make up one logical message.  Each physical message has a particular flag set to indicate it is part of a group and contains a sequence number to indicate it’s position within the group.  Additionally, the message has a Group ID property that indicates the particular logical message group it belongs to.  For example, a grouped message may look like this:

LogicalMessage

Here we have 5 separate physical messages that are all part of the same logical message.

So, the project I was asked to help out with had been having some problems reading these logical messages.  Basically, when a message that was part of a logical group was read off of a queue, it would have this garbage header data at the beginning of the message.  The screenshot below shows the content of a message dumped to the Immediate window in Visual Studio, with the garbage header highlighted in red.

image

I’m a novice when it comes to MQ and in fact my only experience has been using MQ via BizTalk, I’d never looked at the API before.  I dove in and started writing some code to see if I could read these messages and avoid the garbage data.  After considerable trial and error, I came up with the following which seems to work quite well:

  1: MQGetMessageOptions options = new MQGetMessageOptions
  2: {
  3:     Options = MQC.MQGMO_LOGICAL_ORDER | MQC.MQGMO_ALL_MSGS_AVAILABLE | MQC.MQGMO_SYNCPOINT,
  4:     MatchOptions = MQC.MQMO_NONE
  5: };
  6: 
  7: MQQueueManager qManager = new MQQueueManager("<your queue mgr>", 
  8:                                              "<your channel name>", 
  9:                                              "<your server name>");
 10: MQQueue queue = qManager.AccessQueue("<your queue name>",
 11:     MQC.MQOO_INPUT_AS_Q_DEF + MQC.MQOO_FAIL_IF_QUIESCING);
 12: 
 13: MQMessage message = new MQMessage
 14: {
 15:     Format = MQC.MQFMT_STRING,
 16:     Version = MQC.MQMD_VERSION_2
 17: };
 18: 
 19: using (StreamWriter writer = new StreamWriter(Guid.NewGuid().ToString() + ".txt"))
 20: {
 21:     do
 22:     {
 23:         queue.Get(message, options);
 24:         options.MatchOptions = MQC.MQMO_MATCH_GROUP_ID;
 25:         string content = message.ReadString(message.DataLength);
 26:         Console.WriteLine(content);
 27:         writer.WriteLine(content);
 28:     }
 29:     while (options.GroupStatus != MQC.MQGS_LAST_MSG_IN_GROUP);
 30: }
 31: queue.Close();
 32: qManager.Disconnect();

It seems that the key to getting rid of the garbage data at the beginning of the message was settings MQMessage.Version to MQC.MQMD_VERSION_2.

Obviously a big concern would be what happens if you’re reading a grouped message and encounter an exception before you’ve reached the last segment.  Since reading a message from a queue causes that message to be removed from the queue, this could be a real problem.  What you need is a way to read segmented messages in a transactional manner.  This is what the MQC.MQGMO_SYNCPOINT flag gets you, all calls to MQQueue.Get will be treated as a single unit of work that is either committed or rolled back.