예제 #1
0
        /// <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();
            }
        }
예제 #2
0
        internal static bool TryGetHandle(this QueueTransaction transaction, out IntPtr handle)
        {
            if (transaction == null)
            {
                handle = IntPtr.Zero;
                return(true);
            }
            var fake = transaction as QueueTransaction.SpecialTransaction;

            if (fake != null)
            {
                handle = fake.SpecialId;
                return(true);
            }
            handle = IntPtr.Zero;
            return(false);
        }
예제 #3
0
 /// <summary>Tries to read the current message from the queue without removing the message from the queue.</summary>
 /// <remarks>Within a transaction you cannot peek a message that you moved to a subqueue</remarks>
 /// <param name="properties">The properties to read</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 receive times out</returns>
 public Message Peek(Properties properties = Properties.All, TimeSpan?timeout = null, QueueTransaction transaction = null)
 {
     return(Receive(properties, ReadAction.PeekCurrent, timeout, transaction, CursorHandle.None));
 }
예제 #4
0
        /// <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);
            }
        }
예제 #5
0
        /// <summary>
        /// Uses a <see cref="QueueCursor"/> to look for messages with a matching <paramref name="correlationId"/>
        /// Returns the matching message or NULL if no matching message can be found with the allowed <paramref name="timeout"/>.
        /// </summary>
        public static async Task <Message> ReadByCorrelationIdAsync(this QueueReader queue, MessageId correlationId, Properties properties = Properties.All, TimeSpan?timeout = null, QueueTransaction transaction = null)
        {
            timeout = timeout ?? QueueReader.Infinite;
            var start = DateTime.UtcNow;

            using (var cur = new QueueCursor(queue))
            {
                var msg = await cur.PeekAsync(Properties.CorrelationId | Properties.LookupId, timeout);

                for (;;)
                {
                    if (msg == null)
                    {
                        return(null);
                    }

                    if (msg.CorrelationId == correlationId)
                    {
                        return(queue.Lookup(properties, msg.LookupId, LookupAction.ReceiveCurrent, TimeSpan.Zero, transaction));
                    }

                    var elapsed   = DateTime.UtcNow - start;
                    var remaining = timeout - elapsed;
                    if (remaining <= TimeSpan.Zero)
                    {
                        return(null);
                    }

                    msg = await cur.PeekNextAsync(Properties.CorrelationId | Properties.LookupId, remaining);
                }
            }
        }
예제 #6
0
 /// <summary>Tries to receive a message from the queue</summary>
 /// <remarks>Within a transaction you cannot receive a message that you moved to a subqueue</remarks>
 /// <param name="properties">The properties to read</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 receive times out</returns>
 public Message Read(Properties properties = Properties.All, TimeSpan?timeout = null, QueueTransaction transaction = null)
 {
     return(_reader.Receive(properties, ReadAction.Receive, timeout, transaction, _cursorHandle));
 }
예제 #7
0
        /// <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);
            }
        }