# IBM MQ simple sender/receiver This sample demonstrates the basics of sending and receiving messages with the IBM MQ transport. A send-only **Sender** endpoint dispatches `MyMessage` commands to a **Receiver** endpoint, which processes each message with a simulated delay. The sample includes: - A **Sender** console application configured as a send-only endpoint that sends a user-specified number of messages - A **Receiver** console application that processes incoming messages - A **Shared** library containing the message contract ## Prerequisites The sample requires a running IBM MQ broker. A Docker Compose file is included: ```bash docker compose up -d ``` This starts IBM MQ with queue manager `QM1` on port `1414`. The management console is available at `https://localhost:9443/ibmmq/console` (credentials: `admin` / `passw0rd`). ## Running the sample 1. Start the **Receiver** project first. It calls `EnableInstallers()` on startup, which creates any missing queues automatically. 2. Start the **Sender** project. 3. Enter a number in the Sender console and press Enter. That many `MyMessage` commands are sent to the Receiver. 4. The Receiver logs `Start ` when each message begins processing, then `End: ` after a simulated 200 ms delay. ## Code walk-through ### Sender configuration Both endpoints initialise an `IBMMQTransport` instance with the connection details for the local broker: ```cs var ibmmq = new IBMMQTransport() { QueueManagerName = "QM1", Host = "localhost", Port = 1414, Channel = "DEV.ADMIN.SVRCONN", User = "admin", Password = "passw0rd" }; var endpointB = new EndpointConfiguration("DEV.SENDER");//upper case by convention for queues in IBM MQ endpointB.SendFailedMessagesTo("error"); endpointB.UseTransport(ibmmq); endpointB.UseSerialization(); // the Sender sends messages invoking SendOnly results and no receive infrastructure will be set up endpointB.SendOnly(); builder.Services.AddNServiceBusEndpoint(endpointB); ``` The connection properties correspond to the Docker Compose defaults: queue manager `QM1`, host `localhost`, port `1414`, channel `DEV.ADMIN.SVRCONN`. The Sender is also configured with `SendOnly()`, which prevents NServiceBus from creating an input queue for the Sender process. ### Creating a message The message being sent is the following record type, inheriting `IMessage` type from NServiceBus. This sample uses a record type but NServiceBus supports [interfaces and classess as message types](/nservicebus/messaging/index.md#messaging-concepts-in-nservicebus). ```cs public record MyMessage(string Data) : IMessage; ``` ### Sending a message ```cs var message = new MyMessage(Data: "MyData"); Console.WriteLine($"Sending message: {message}"); await instance.Send("DEV.RECEIVER", message); ``` ### Receiver configuration ```cs var endpointB = new EndpointConfiguration("DEV.RECEIVER"); endpointB.UseTransport(ibmmq); endpointB.UseSerialization(); endpointB.EnableInstallers(); // Delayed retries must be disabled as the IBM MQ transport does not support them endpointB.Recoverability().Delayed(settings => settings.NumberOfRetries(0)); builder.Services.AddNServiceBusEndpoint(endpointB); ``` `EnableInstallers()` creates the `DEV.RECEIVER` queue on the broker if it does not already exist. Delayed retries are disabled so that any processing failures move messages directly to the error queue without cycling through retry delays. ### Message handler ```cs sealed class MyHandler : IHandleMessages { public async Task Handle(MyMessage message, IMessageHandlerContext context) { Console.WriteLine($"Start {message.Data}"); await Task.Delay(200, context.CancellationToken); Console.WriteLine($"End: {message.Data}"); } } ``` `MyHandler` simulates a 200 ms processing delay. The `CancellationToken` from `context.CancellationToken` is forwarded to `Task.Delay` so the handler responds promptly to endpoint shutdown.