/// <summary> /// Sends the given transport message to the specified destination address using MSMQ. Will use the existing <see cref="MessageQueueTransaction"/> stashed /// under the <see cref="CurrentTransactionKey"/> key in the given <paramref name="context"/>, or else it will create one and add it. /// </summary> public async Task Send(string destinationAddress, TransportMessage message, ITransactionContext context) { if (destinationAddress == null) { throw new ArgumentNullException(nameof(destinationAddress)); } if (message == null) { throw new ArgumentNullException(nameof(message)); } if (context == null) { throw new ArgumentNullException(nameof(context)); } var logicalMessage = CreateMsmqMessage(message); var messageQueueTransaction = context.GetOrAdd(CurrentTransactionKey, () => { var transaction = new MessageQueueTransaction(); transaction.Begin(); context.OnCommitted(async ctx => transaction.Commit()); return(transaction); }); var sendQueues = context.GetOrAdd(CurrentOutgoingQueuesKey, () => { var messageQueues = new ConcurrentDictionary <string, MessageQueue>(StringComparer.InvariantCultureIgnoreCase); context.OnDisposed(ctx => { foreach (var messageQueue in messageQueues.Values) { messageQueue.Dispose(); } }); return(messageQueues); }); var path = MsmqUtil.GetFullPath(destinationAddress); var sendQueue = sendQueues.GetOrAdd(path, _ => { var messageQueue = new MessageQueue(path, QueueAccessMode.Send); return(messageQueue); }); try { sendQueue.Send(logicalMessage, messageQueueTransaction); } catch (Exception exception) { throw new RebusApplicationException(exception, $"Could not send to MSMQ queue with path '{sendQueue.Path}'"); } }