File: System\ServiceModel\Channels\MsmqReceiveContext.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.ServiceModel.Channels
{
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.ServiceModel;
    using System.Transactions;
    using System.ServiceModel.Dispatcher;
    using System.Threading;
    using System.Runtime;
 
    class MsmqReceiveContextSettings : IReceiveContextSettings
    {
        public MsmqReceiveContextSettings()
        {
            ValidityDuration = MsmqDefaults.ValidityDuration;
        }
 
        public MsmqReceiveContextSettings(IReceiveContextSettings toBeCloned)
        {
            Enabled = toBeCloned.Enabled;
            ValidityDuration = toBeCloned.ValidityDuration;
        }
 
        public TimeSpan ValidityDuration
        {
            get;
            private set;
        }
 
        public bool Enabled
        {
            get;
            set;
        }
 
        internal void SetValidityDuration(TimeSpan validityDuration)
        {
            ValidityDuration = validityDuration;
        }
    }
 
    class MsmqReceiveContext : ReceiveContext
    {
        long lookupId;
        DateTime expiryTime;
        MsmqReceiveContextLockManager manager;
 
        public MsmqReceiveContext(long lookupId, DateTime expiryTime, MsmqReceiveContextLockManager manager)
            : base()
        {
            this.manager = manager;
            this.lookupId = lookupId;
            this.expiryTime = expiryTime;
        }
 
        public long LookupId
        {
            get
            {
                return this.lookupId;
            }
        }
 
        public DateTime ExpiryTime
        {
            get
            {
                return this.expiryTime;
            }
        }
 
        public MsmqReceiveContextLockManager Manager
        {
            get
            {
                return this.manager;
            }
        }
 
        public void MarkContextExpired()
        {
            base.Fault();
        }
 
        protected override void OnComplete(TimeSpan timeout)
        {
            this.manager.DeleteMessage(this, timeout);
        }
 
        protected override void OnAbandon(TimeSpan timeout)
        {
            this.manager.UnlockMessage(this, timeout);
        }
 
        protected override IAsyncResult OnBeginComplete(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return ReceiveContextAsyncResult.CreateComplete(this, timeout, callback, state);
        }
 
        protected override void OnEndComplete(IAsyncResult result)
        {
            ReceiveContextAsyncResult.End(result);
        }
 
        protected override IAsyncResult OnBeginAbandon(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return ReceiveContextAsyncResult.CreateAbandon(this, timeout, callback, state);
        }
 
        protected override void OnEndAbandon(IAsyncResult result)
        {
            ReceiveContextAsyncResult.End(result);
        }
 
        class ReceiveContextAsyncResult : AsyncResult
        {
            MsmqReceiveContext receiver;
            TimeoutHelper timeoutHelper;
            static Action<object> onComplete;
            static Action<object> onAbandon;
            Transaction associatedTransaction;
 
            ReceiveContextAsyncResult(MsmqReceiveContext receiver, TimeSpan timeout, AsyncCallback callback, object state, Action<object> target)
                : base(callback, state)
            {
                this.timeoutHelper = new TimeoutHelper(timeout);
                this.receiver = receiver;
 
                if (Transaction.Current != null)
                {
                    this.associatedTransaction = Transaction.Current;
                }
 
                ActionItem.Schedule(target, this);
            }
 
            public static IAsyncResult CreateComplete(MsmqReceiveContext receiver, TimeSpan timeout, AsyncCallback callback, object state)
            {
                if (onComplete == null)
                {
                    onComplete = new Action<object>(OnComplete);
                }
                return new ReceiveContextAsyncResult(receiver, timeout, callback, state, onComplete);
            }
 
            public static IAsyncResult CreateAbandon(MsmqReceiveContext receiver, TimeSpan timeout, AsyncCallback callback, object state)
            {
                if (onAbandon == null)
                {
                    onAbandon = new Action<object>(OnAbandon);
                }
                return new ReceiveContextAsyncResult(receiver, timeout, callback, state, onAbandon);
            }
 
            static void OnComplete(object parameter)
            {
                ReceiveContextAsyncResult result = parameter as ReceiveContextAsyncResult;
                Exception completionException = null;
                Transaction savedTransaction = null;
                try
                {
                    // set the current transaction object for this worker thread as this operation could
                    // have been scheduled by another worker thread. We do not want to complete in
                    // worker threads ambient transaction. associatedTransaction can be null. 
                    savedTransaction = Transaction.Current;
                    Transaction.Current = result.associatedTransaction;
                    result.receiver.OnComplete(result.timeoutHelper.RemainingTime());
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    }
                    completionException = e;
                }
                finally
                {
                    Transaction.Current = savedTransaction;
                }
                result.Complete(false, completionException);
            }
 
            static void OnAbandon(object parameter)
            {
                ReceiveContextAsyncResult result = parameter as ReceiveContextAsyncResult;
                Exception completionException = null;
                try
                {
                    result.receiver.OnAbandon(result.timeoutHelper.RemainingTime());
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                        throw;
                    completionException = e;
                }
                result.Complete(false, completionException);
            }
 
            public static void End(IAsyncResult result)
            {
                AsyncResult.End<ReceiveContextAsyncResult>(result);
            }
        }
    }
}