Communication with IBM MQ in .Net Core 3.0

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 the MQQueue class.
  • AccessTopic returns an instance of the MQTopic 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!

 

Leave A Comment

Programming isn’t just writing code; it’s a lens through which we redefine the world.

Programming isn’t just writing code; it’s a lens through which we redefine the world.