File: System\ServiceModel\Channels\ChannelDemuxer.cs
Web Access
Project: src\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
 
 
namespace System.ServiceModel.Channels
{
    internal class ChannelDemuxer
    {
        public readonly static TimeSpan UseDefaultReceiveTimeout = TimeSpan.MinValue;
 
        public ChannelDemuxer()
        {
            PeekTimeout = ChannelDemuxer.UseDefaultReceiveTimeout; //use the default receive timeout (original behavior)
            MaxPendingSessions = 10;
        }
 
        public TimeSpan PeekTimeout { get; set; }
 
        public int MaxPendingSessions { get; set; }
    }
 
    //
    // Binding element
    //
 
    internal class ChannelDemuxerBindingElement : BindingElement
    {
        private ChannelDemuxer _demuxer;
        private CachedBindingContextState _cachedContextState;
        private bool _cacheContextState;
 
        public ChannelDemuxerBindingElement(bool cacheContextState)
        {
            _cacheContextState = cacheContextState;
            if (cacheContextState)
            {
                _cachedContextState = new CachedBindingContextState();
            }
            _demuxer = new ChannelDemuxer();
        }
 
        public ChannelDemuxerBindingElement(ChannelDemuxerBindingElement element)
        {
            _demuxer = element._demuxer;
            _cacheContextState = element._cacheContextState;
            _cachedContextState = element._cachedContextState;
        }
 
        public TimeSpan PeekTimeout
        {
            get
            {
                return _demuxer.PeekTimeout;
            }
            set
            {
                if (value < TimeSpan.Zero && value != ChannelDemuxer.UseDefaultReceiveTimeout)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(value)));
                }
 
                _demuxer.PeekTimeout = value;
            }
        }
 
        public int MaxPendingSessions
        {
            get
            {
                return _demuxer.MaxPendingSessions;
            }
            set
            {
                if (value < 1)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(value), SRP.ValueMustBeGreaterThanZero));
                }
 
                _demuxer.MaxPendingSessions = value;
            }
        }
 
        private void SubstituteCachedBindingContextParametersIfNeeded(BindingContext context)
        {
            if (!_cacheContextState)
            {
                return;
            }
            if (!_cachedContextState.IsStateCached)
            {
                foreach (object parameter in context.BindingParameters)
                {
                    _cachedContextState.CachedBindingParameters.Add(parameter);
                }
                _cachedContextState.IsStateCached = true;
            }
            else
            {
                context.BindingParameters.Clear();
                foreach (object parameter in _cachedContextState.CachedBindingParameters)
                {
                    context.BindingParameters.Add(parameter);
                }
            }
        }
 
        public override IChannelFactory<TChannel> BuildChannelFactory<TChannel>(BindingContext context)
        {
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(context));
            }
 
            SubstituteCachedBindingContextParametersIfNeeded(context);
            return context.BuildInnerChannelFactory<TChannel>();
        }
 
        public override bool CanBuildChannelFactory<TChannel>(BindingContext context)
        {
            if (context == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(context));
            }
 
            return context.CanBuildInnerChannelFactory<TChannel>();
        }
 
        public override BindingElement Clone()
        {
            return new ChannelDemuxerBindingElement(this);
        }
 
        public override T GetProperty<T>(BindingContext context)
        {
            // augment the context with cached binding parameters
            if (_cacheContextState && _cachedContextState.IsStateCached)
            {
                for (int i = 0; i < _cachedContextState.CachedBindingParameters.Count; ++i)
                {
                    if (!context.BindingParameters.Contains(_cachedContextState.CachedBindingParameters[i].GetType()))
                    {
                        context.BindingParameters.Add(_cachedContextState.CachedBindingParameters[i]);
                    }
                }
            }
            return context.GetInnerProperty<T>();
        }
 
        private class CachedBindingContextState
        {
            public bool IsStateCached;
            public BindingParameterCollection CachedBindingParameters;
 
            public CachedBindingContextState()
            {
                CachedBindingParameters = new BindingParameterCollection();
            }
        }
    }
}