File: System\ServiceModel\OperationContextScope.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
 
namespace System.ServiceModel
{
    using System;
    using System.ServiceModel.Channels;
    using System.Threading;
 
    public sealed class OperationContextScope : IDisposable
    {
        [ThreadStatic]
        static OperationContextScope legacyCurrentScope;
 
        static AsyncLocal<OperationContextScope> currentScope = new AsyncLocal<OperationContextScope>();
 
        OperationContext currentContext;
        bool disposed;
        readonly OperationContext originalContext = OperationContext.Current;
        readonly OperationContextScope originalScope = OperationContextScope.CurrentScope;
        readonly Thread thread = Thread.CurrentThread;
 
        public OperationContextScope(IContextChannel channel)
        {
            this.PushContext(new OperationContext(channel));
        }
 
        public OperationContextScope(OperationContext context)
        {
            this.PushContext(context);
        }
 
        private static OperationContextScope CurrentScope
        {
            get
            {
                return ServiceModelAppSettings.DisableOperationContextAsyncFlow ? legacyCurrentScope : currentScope.Value;
            }
 
            set
            {
                if (ServiceModelAppSettings.DisableOperationContextAsyncFlow)
                {
                    legacyCurrentScope = value;
                }
                else
                {
                    currentScope.Value = value;
                }
            }
        }
 
        public void Dispose()
        {
            if (!this.disposed)
            {
                this.disposed = true;
                this.PopContext();
            }
        }
 
        void PushContext(OperationContext context)
        {
            bool isAsyncFlowEnabled = OperationContext.ShouldUseAsyncLocalContext;
 
            this.currentContext = context;
 
            if (isAsyncFlowEnabled)
            {
                OperationContext.EnableAsyncFlow(this.currentContext);
            }
 
            CurrentScope = this;
            OperationContext.Current = this.currentContext;
        }
 
        void PopContext()
        {
            if (ServiceModelAppSettings.DisableOperationContextAsyncFlow && this.thread != Thread.CurrentThread)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidContextScopeThread0)));
 
            if (CurrentScope != this)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInterleavedContextScopes0)));
 
            if (OperationContext.Current != this.currentContext)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxContextModifiedInsideScope0)));
 
            CurrentScope = this.originalScope;
            OperationContext.Current = this.originalContext;
 
            if (this.currentContext != null)
                this.currentContext.SetClientReply(null, false);
        }
    }
}