Communication with IBM MQ in .Net Core 3.0

September 7, 2020
Introduction
Using message queues is one of the most effective ways to enable communication between different modules in a microservices solution.
In this approach, communication is decoupled from the recipient — the recipient can even be offline when a message is published. Once the recipient comes online, it can retrieve the message from the queue.
Message queuing systems also allow multiple recipients to listen to a single sender, and a single recipient to listen to multiple senders.
Implementing such flexibility is very difficult and complex with traditional synchronous communication.
And these are just some of the powerful features that message queues offer.
Background
For a long time, our team used RabbitMQ for the Message Queueing system. Although RabbitMq is a system with many benefits, our current client uses a Warehouse Management System that connects to other systems via IBM MQ . Although the basics of using the Message Queue systems were the same, but there were many challenges to using the IBM MQ.
The IBM MQ system is an Enterprise system. The vast majority of related documents are written primarily for Java, which makes it difficult for a .NET developer to work with this system.
Installation
The first challenge when working with IBM MQ is installing it on a Windows operating system, which can create significant system security challenges — especially when the system is part of an Active Directory environment, making setup much more complicated.
For development and testing purposes, I highly recommend installing IBM MQ using Docker. IBM provides a very complete and efficient installation guide, which you can find here: Get an IBM MQ queue for development in a container.
After installing IBM MQ via Docker, here is some useful default information that may not be easy to find in IBM’s official documentation:
- Host name: localhost (port 1414)
- Queue manager: QM1
- Queue: DEV.QUEUE.1
- Channel: DEV.APP.SVRCONN
- Port: 1414
- Integration User ID: app
- Integration Password: passw0rd
- Management Console: https://localhost:9443/ibmmq/console/
- Admin User: admin
- Admin Password: passw0rd
Connection Structure
As I mentioned, working with the IBM MQ is not so easy. Although IBM MQ provides a very efficient NuGet for developing applications under .Net, working with this library is not easy and requires deep knowledge and familiarity with IBM MQ.
In short, you are able to connect to the Topic or the Queue in IBM MQ via the Channel. You connect to Queue Manager via Channel. Queue Manager is actually a specific instance in IBM MQ. This means that you can have several Queue Managers. Each Queue Manager can have a number of Channels through which communication with the Queue Manager is established.

Code Guide
Initialize the connection properties
The library I designed simplifies the connection process through the IbmMqProxyConnectionConfiguration
class.
In the next step, you need to create an instance of the IbmMqProxy
class, which facilitates communication with IBM MQ.
While I will also introduce how to use the official IBM-provided NuGet package, for simple communications, using this proxy is highly recommended.
Listening to a Queue/Topic (MQDestination)
In the next step, you need to create an instance of the MQQueueManager
class. To do this, you must provide the queue manager’s name along with the basic connection properties, stored in a Hashtable
.
The MQQueueManager
class provides two methods: AccessQueue
and AccessTopic
.
AccessQueue
returns an instance of theMQQueue
class.AccessTopic
returns an instance of theMQTopic
class.
Both MQQueue
and MQTopic
inherit from a base class called MQDestination
.
When accessing either of them, you must specify the purpose of opening the connection. This is done using constants such as MQC.MQTOPIC_OPEN_AS_SUBSCRIPTION
.MQC
is a static class within the IBM.WMQ
namespace that provides many constants used when working with IBM MQ.
You can open a connection for one of the following two purposes:
MQTOPIC_OPEN_AS_SUBSCRIPTION = 1
MQTOPIC_OPEN_AS_PUBLICATION = 2
Once the connection is opened, you can use the Get()
method to read incoming messages from either a queue or a topic.
At this point, you should be familiar with the MQException
class, which handles errors related to IBM MQ operations. These errors are typically returned by the IBM MQ command-line tools and come with a specific reason code and description.
One common error occurs when attempting to read from a destination (MQDestination
) with no available messages. In that case, the reason code returned is MQC.MQRC_NO_MSG_AVAILABLE
.
You must handle this case appropriately during the Get()
operation.
Other errors occurring during connection, reading, or writing usually indicate issues with the connection itself.
As shown in the code, when the proxy reads a new message, it triggers a callback method called messageHandler
and passes the received message to it.
If any other connection error occurs, the proxy disconnects from IBM MQ and invokes the connectionStatusChangedHandler
callback method.
Writing to a Queue/Topic (MQDestination)
Writing in an MQDestination is much easier. Basically, like the read method, you have to open an MQDestination via the Access method and then put your message in the Destination with the Put method.
The full source code is available on my GitHub — feel free to explore it!