/// <summary> /// Asks MSMQ to attempt to deliver a message. /// To ensure the message reached the queue you need to check acknowledgement messages sent to the <see cref="Message.AdministrationQueue"/> /// </summary> /// <param name="message">The message to try to send</param> /// <param name="transaction">can be NULL for no transaction, a <see cref="QueueTransaction"/>, <see cref="QueueTransaction.Single"/>, or <see cref="QueueTransaction.Dtc"/>.</param> public void Write(Message message, QueueTransaction transaction = null) { Contract.Requires(message != null); message.Props.PrepareToSend(); var props = message.Props.Allocate(); try { int res; IntPtr txnHandle; if (transaction.TryGetHandle(out txnHandle)) { res = Native.SendMessage(_handle, props, txnHandle); } else { res = Native.SendMessage(_handle, props, transaction.InternalTransaction); } if (Native.IsError(res)) { throw new QueueException(res); } } finally { message.Props.Free(); } }
/// <summary>Move the message specified by <paramref name="lookupId"/> from <paramref name="sourceQueue"/> to the <paramref name="targetQueue"/>.</summary> /// <remarks> /// Moving message is 10 to 100 times faster than sending the message to another queue. /// Within a transaction you cannot receive a message that you moved to a subqueue. /// </remarks> public static void MoveMessage(QueueReader sourceQueue, SubQueue targetQueue, long lookupId, QueueTransaction transaction = null) { Contract.Requires(sourceQueue != null); Contract.Requires(targetQueue != null); if (sourceQueue.IsClosed) { throw new ObjectDisposedException(nameof(sourceQueue)); } if (targetQueue.IsClosed) { throw new ObjectDisposedException(nameof(targetQueue)); } int res; IntPtr txnHandle; if (transaction.TryGetHandle(out txnHandle)) { res = Native.MoveMessage(sourceQueue._handle, targetQueue.MoveHandle, lookupId, txnHandle); } else { res = Native.MoveMessage(sourceQueue._handle, targetQueue.MoveHandle, lookupId, transaction.InternalTransaction); } if (Native.IsError(res)) { throw new QueueException(res); } }
/// <summary>Tries to peek (or receive) a message using the queue-specific <paramref name="lookupId"/></summary> /// <remarks>Within a transaction you cannot receive a message that you moved to a subqueue within the same transaction</remarks> /// <param name="properties">The properties to read</param> /// <param name="lookupId">The <see cref="Message.LookupId"/> of the message to read</param> /// <param name="action">Receive or peek a message?</param> /// <param name="timeout">The time allowed, defaults to infinite. Use <see cref="TimeSpan.Zero"/> to return without waiting</param> /// <param name="transaction">can be NULL for no transaction, a <see cref="QueueTransaction"/>, <see cref="QueueTransaction.Single"/>, or <see cref="QueueTransaction.Dtc"/>.</param> /// <returns>The message, or NULL if the message was not found or the receive times out</returns> public unsafe Message Lookup(Properties properties, long lookupId, LookupAction action = LookupAction.ReceiveCurrent, TimeSpan?timeout = null, QueueTransaction transaction = null) { if (IsClosed) { throw new ObjectDisposedException(nameof(Queue)); } uint timeoutMS = TimeoutInMs(timeout); var msg = new Message(); int res; msg.Props.SetForRead(properties); for (;;) // loop because we might need to adjust memory size { var props = msg.Props.Allocate(); try { IntPtr txnHandle; if (transaction.TryGetHandle(out txnHandle)) { res = Native.ReceiveMessageByLookupId(_handle, lookupId, action, props, null, null, txnHandle); } else { res = Native.ReceiveMessageByLookupId(_handle, lookupId, action, props, null, null, transaction.InternalTransaction); } } finally { msg.Props.Free(); } if ((ErrorCode)res == ErrorCode.IOTimeout || (ErrorCode)res == ErrorCode.MessageNotFound) { return(null); } if (Native.NotEnoughMemory(res)) { msg.Props.IncreaseBufferSize(); continue; // try again } if (Native.IsError(res)) { throw new QueueException(res); } msg.Props.ResizeBody(); return(msg); } }