public void DeleteMessage(MsmqReceiveContext receiveContext, TimeSpan timeout)
        {
            TimeoutHelper helper   = new TimeoutHelper(timeout);
            long          lookupId = receiveContext.LookupId;

            lock (this.internalStateLock)
            {
                if (!this.messageExpiryMap.ContainsKey(lookupId))
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(System.ServiceModel.SR.GetString("MessageValidityExpired", new object[] { lookupId })));
                }
                MsmqReceiveContext item = this.messageExpiryMap[lookupId];
                if (DateTime.UtcNow > item.ExpiryTime)
                {
                    item.MarkContextExpired();
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(System.ServiceModel.SR.GetString("MessageValidityExpired", new object[] { lookupId })));
                }
                ((ILockingQueue)this.queue).DeleteMessage(lookupId, helper.RemainingTime());
                if (Transaction.Current != null)
                {
                    List <MsmqReceiveContext> list;
                    if (!this.transMessages.TryGetValue(Transaction.Current.TransactionInformation.DistributedIdentifier, out list))
                    {
                        list = new List <MsmqReceiveContext>();
                        this.transMessages.Add(Transaction.Current.TransactionInformation.DistributedIdentifier, list);
                        Transaction.Current.TransactionCompleted += this.transactionCompletedHandler;
                    }
                    list.Add(item);
                }
                else
                {
                    this.messageExpiryMap.Remove(lookupId);
                }
            }
        }
        // tx aborts can ---- with DeleteMessage but this ---- is harmless because
        //  - internal state changes are protected via the internalStateLock
        //  - we do not have an ordering requirement between DeleteMessage and a tx abort
        //
        // tx commits cannot ---- with DeleteMessage as the ReceiveContext state machine does not allow
        // DeleteMessage calls if the tx holding this lock committed
        public void DeleteMessage(MsmqReceiveContext receiveContext, TimeSpan timeout)
        {
            TimeoutHelper helper   = new TimeoutHelper(timeout);
            long          lookupId = receiveContext.LookupId;

            lock (this.internalStateLock)
            {
                // Expiry map is first checked before calling ReceiveContextExists as we need to throw
                // validity expired exception if the lookup id is not in the map.
                if (this.messageExpiryMap.ContainsKey(lookupId))
                {
                    Fx.Assert(ReceiveContextExists(receiveContext), "Mismatch between the receive context object stored in the map and the object passed to the method");
                    MsmqReceiveContext entry = this.messageExpiryMap[lookupId];
                    if (DateTime.UtcNow > entry.ExpiryTime)
                    {
                        entry.MarkContextExpired();
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MessageValidityExpired, lookupId)));
                    }
                    else
                    {
                        ((ILockingQueue)this.queue).DeleteMessage(lookupId, helper.RemainingTime());

                        if (Transaction.Current != null)
                        {
                            List <MsmqReceiveContext> transMsgs;
                            if (!this.transMessages.TryGetValue(Transaction.Current.TransactionInformation.DistributedIdentifier, out transMsgs))
                            {
                                transMsgs = new List <MsmqReceiveContext>();
                                this.transMessages.Add(Transaction.Current.TransactionInformation.DistributedIdentifier, transMsgs);
                                // only need to attach the tx complete handler once per transaction
                                Transaction.Current.TransactionCompleted += this.transactionCompletedHandler;
                            }
                            transMsgs.Add(entry);
                        }
                        else
                        {
                            this.messageExpiryMap.Remove(lookupId);
                        }
                    }
                }
                else
                {
                    // it was cleaned up by the expiry timer
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MsmqException(SR.GetString(SR.MessageValidityExpired, lookupId)));
                }
            }
        }