We are using IBM MQ XMS C# client ver 9.0 (on .NET 4.6.2 framework) to work with IBM MQ. I just need to know of all the messages on a given queue without removing them off the queue.
We also got the Consumers set up for the queue. Need both consumers & browsers working in tandem. Browser should not remove messages but still need to get all the messages.
So I have set up a QueueBrowser like below, but queueBrowser.GetEnumerator() doesn't get messages at all.
With the same code if Create a MessageConsumer and attach a listener, it will get the messages posted the queue. So issue with QueueBrowser only.
Can anyone point out why its happening like this. Why queueEnumerator.MoveNext() always return false, indicating no messages on the queue.
XMSFactoryFactory xMSFactoryFactory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);
// Create WMQ Connection Factory.
IConnectionFactory connectionFactory = xMSFactoryFactory.CreateConnectionFactory();
connectionFactory.SetStringProperty(XMSC.WMQ_HOST_NAME, "hostname");
connectionFactory.SetIntProperty(XMSC.WMQ_PORT, portNumber);
connectionFactory.SetStringProperty(XMSC.WMQ_CHANNEL, "channelName");
connectionFactory.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT);
connectionFactory.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, "QueueManagerName");
// Create connection.
connectionWMQ = connectionFactory.CreateConnection();
connectionWMQ.ExceptionListener = new ExceptionListener(OnXMSException);
// Create session
ISession sessionWMQ = connectionWMQ.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
IDestination destination = sessionWMQ.CreateQueue("QueueName");
IQueueBrowser queueBrowser = sessionWMQ.CreateBrowser(destination);
connectionWMQ.Start();
Thread thread = new Thread(KeepBrowsingMessaegs);
thread.Start();
--end of the method
private void KeepBrowsingMessaegs()
{
IEnumerator queueEnumerator = queueBrowser.GetEnumerator();
while (!cancellationTokenSource.IsCancellationRequested)
{
if (queueEnumerator.MoveNext())
{
ITextMessage textMessage = queueEnumerator.Current as ITextMessage;
if (textMessage != null)
{
System.Diagnostics.Trace.Write(textMessage);
}
}
}
}
OP mentioned the following in the comments: We have consumers running to read the message as part of business case and want to set up browser so that we just get a copy of message so that we can track it in a separate application to log of all the message received.
I am providing some options below.
Option 1
Do not have a separate application just for the purpose of log the messages received, instead have your "business case" application log the messages as part of the processing.
Option 2
Setup two queues, the first would receive the inbound messages and be consumed by an application that would log the messages and then put a copy of it to a second queue which would be consumed by your "business case" application.
Option 3
Use IBM MQ pub/sub features to create two copies of the message, one of which will be consumed by an application that would log the messages and the other would be consumed by your "business case" application. Note this only copies the message body, the MQ Message Descriptor (MQMD) which is meta data about the messages (things like put time, put date, message id, userid) will not be duplicated. Many apps do not look at the MQMD so it may not be a issue for you.
The setup would look like this:
Create a QALIAS
for the inbound messages, this alias will point to a topic string by specifying the target is a topic object:
DEFINE QALIAS(INBOUND.QUEUE) TARGET(INBOUND.TOPIC) TARGTYPE(TOPIC)
Define the TOPIC
object:
DEFINE TOPIC(INBOUND.TOPIC) TOPICSTR(INBOUND/TOPIC)
Create two QLOCAL
objects, one to be consumed by the application that would log the messages and the other to be consumed by your "business case" application:
DEFINE QLOCAL(INBOUND.QUEUE.LOGGER)
DEFINE QLOCAL(INBOUND.QUEUE.PROCESSOR)
Define two administrative SUBSCRIPTION
objects to subscribe both queues to the topic topic string:
DEFINE SUB(INBOUND.QUEUE.LOGGER.SUB) TOPICSTR(INBOUND/TOPIC) DEST(INBOUND.QUEUE.LOGGER)
DEFINE SUB(INBOUND.QUEUE.PROCESSOR.SUB) TOPICSTR(INBOUND/TOPIC) DEST(INBOUND.QUEUE.PROCESSOR)
The result of the above setup is that every message that is put to a queue called INBOUND.QUEUE
will have a copy published to the two queues INBOUND.QUEUE.LOGGER
and INBOUND.QUEUE.PROCESSOR
.
Option 4
You could setup three QLOCAL
objects, one would be the queue for inbound messages, you would have a program read from this queue and then write a copy of the message to the other two queues. There is an open source tool maintained by Capitalware called Message Multiplexer (MMX) which can read from a source queue and write to one or more queues, this does duplicate the MQMD along with the message body.
The setup would look like this:
Create three QLOCAL
objects, the first one to be consumed an application which will make a copy to the second to be consumed by the application that would log the messages and the third to be consumed by your "business case" application:
DEFINE QLOCAL(INBOUND.QUEUE)
DEFINE QLOCAL(INBOUND.QUEUE.LOGGER)
DEFINE QLOCAL(INBOUND.QUEUE.PROCESSOR)
Option 5
There is a commercial product called MQ Message Replication (MQMR) that can make an exact copy of the message going to your "business case" application queue to one or more other queues using a MQ API exit. I have not used this personally but the setup would be just two QLOCAL queues, the first would be consumed by your "business case" application, the second would be consumed by the application that would log the messages.
DEFINE QLOCAL(INBOUND.QUEUE)
DEFINE QLOCAL(INBOUND.QUEUE.LOGGER)