File: System\ServiceModel\Channels\ReliableChannelFactory.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;
    using System.ServiceModel;
 
    class ReliableChannelFactory<TChannel, InnerChannel> : ChannelFactoryBase<TChannel>, IReliableFactorySettings
        where InnerChannel : class, IChannel
    {
        TimeSpan acknowledgementInterval;
        FaultHelper faultHelper;
        bool flowControlEnabled;
        TimeSpan inactivityTimeout;
        int maxPendingChannels;
        int maxRetryCount;
        int maxTransferWindowSize;
        MessageVersion messageVersion;
        bool ordered;
        ReliableMessagingVersion reliableMessagingVersion;
 
        IChannelFactory<InnerChannel> innerChannelFactory;
 
        public ReliableChannelFactory(ReliableSessionBindingElement settings, IChannelFactory<InnerChannel> innerChannelFactory, Binding binding)
            : base(binding)
        {
            this.acknowledgementInterval = settings.AcknowledgementInterval;
            this.flowControlEnabled = settings.FlowControlEnabled;
            this.inactivityTimeout = settings.InactivityTimeout;
            this.maxPendingChannels = settings.MaxPendingChannels;
            this.maxRetryCount = settings.MaxRetryCount;
            this.maxTransferWindowSize = settings.MaxTransferWindowSize;
            this.messageVersion = binding.MessageVersion;
            this.ordered = settings.Ordered;
            this.reliableMessagingVersion = settings.ReliableMessagingVersion;
 
            this.innerChannelFactory = innerChannelFactory;
            this.faultHelper = new SendFaultHelper(binding.SendTimeout, binding.CloseTimeout);
        }
 
        public TimeSpan AcknowledgementInterval
        {
            get { return this.acknowledgementInterval; }
        }
 
        public FaultHelper FaultHelper
        {
            get { return this.faultHelper; }
        }
 
        public bool FlowControlEnabled
        {
            get { return this.flowControlEnabled; }
        }
 
        public TimeSpan InactivityTimeout
        {
            get { return this.inactivityTimeout; }
        }
 
        protected IChannelFactory<InnerChannel> InnerChannelFactory
        {
            get { return this.innerChannelFactory; }
        }
 
        public int MaxPendingChannels
        {
            get { return this.maxPendingChannels; }
        }
 
        public int MaxRetryCount
        {
            get { return this.maxRetryCount; }
        }
 
        public MessageVersion MessageVersion
        {
            get { return this.messageVersion; }
        }
 
        public int MaxTransferWindowSize
        {
            get { return this.maxTransferWindowSize; }
        }
 
        public bool Ordered
        {
            get { return this.ordered; }
        }
 
        public ReliableMessagingVersion ReliableMessagingVersion
        {
            get { return this.reliableMessagingVersion; }
        }
 
        public override T GetProperty<T>()
        {
            if (typeof(T) == typeof(IChannelFactory<TChannel>))
            {
                return (T)(object)this;
            }
 
            T baseProperty = base.GetProperty<T>();
            if (baseProperty != null)
            {
                return baseProperty;
            }
 
            return this.innerChannelFactory.GetProperty<T>();
        }
 
        public TimeSpan SendTimeout
        {
            get { return this.InternalSendTimeout; }
        }
 
        protected override void OnAbort()
        {
            // Aborting base first to abort channels. Must abort higher channels before aborting lower channels.
            base.OnAbort();
            this.faultHelper.Abort();
            this.innerChannelFactory.Abort();
        }
 
        protected override void OnOpen(TimeSpan timeout)
        {
            this.innerChannelFactory.Open(timeout);
        }
 
        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return this.innerChannelFactory.BeginOpen(callback, state);
        }
 
        protected override void OnEndOpen(IAsyncResult result)
        {
            this.innerChannelFactory.EndOpen(result);
        }
 
        protected override void OnClose(TimeSpan timeout)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            // Closing base first to close channels.  Must close higher channels before closing lower channels.
            base.OnClose(timeoutHelper.RemainingTime());
            this.faultHelper.Close(timeoutHelper.RemainingTime());
            this.innerChannelFactory.Close(timeoutHelper.RemainingTime());
        }
 
        protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        {
            // Closing base first to close channels.  Must close higher channels before closing lower channels.
            return OperationWithTimeoutComposer.BeginComposeAsyncOperations(
                timeout,
                new OperationWithTimeoutBeginCallback[] 
                {
                    new OperationWithTimeoutBeginCallback(base.OnBeginClose),
                    new OperationWithTimeoutBeginCallback(this.faultHelper.BeginClose),
                    new OperationWithTimeoutBeginCallback(this.innerChannelFactory.BeginClose) 
                },
                new OperationEndCallback[] 
                {
                    new OperationEndCallback(base.OnEndClose),
                    new OperationEndCallback(this.faultHelper.EndClose),
                    new OperationEndCallback(this.innerChannelFactory.EndClose)
                },
                callback, 
                state);
        }
 
        protected override void OnEndClose(IAsyncResult result)
        {
            OperationWithTimeoutComposer.EndComposeAsyncOperations(result);
        }
 
        protected override TChannel OnCreateChannel(EndpointAddress address, Uri via)
        {
            LateBoundChannelParameterCollection channelParameters = new LateBoundChannelParameterCollection();
 
            IClientReliableChannelBinder binder = ClientReliableChannelBinder<InnerChannel>.CreateBinder(address, via,
                this.InnerChannelFactory, MaskingMode.All,
                TolerateFaultsMode.IfNotSecuritySession, channelParameters, this.DefaultCloseTimeout,
                this.DefaultSendTimeout);
 
            if (typeof(TChannel) == typeof(IOutputSessionChannel))
            {
                if (typeof(InnerChannel) == typeof(IDuplexChannel) || typeof(InnerChannel) == typeof(IDuplexSessionChannel))
                    return (TChannel)(object)new ReliableOutputSessionChannelOverDuplex(this, this, binder, this.faultHelper, channelParameters);
 
                // typeof(InnerChannel) == typeof(IRequestChannel) || typeof(InnerChannel) == typeof(IRequestSessionChannel))
                return (TChannel)(object)new ReliableOutputSessionChannelOverRequest(this, this, binder, this.faultHelper, channelParameters);
            }
            else if (typeof(TChannel) == typeof(IDuplexSessionChannel))
            {
                return (TChannel)(object)new ClientReliableDuplexSessionChannel(this, this, binder, this.faultHelper, channelParameters, WsrmUtilities.NextSequenceId());
            }
 
            // (typeof(TChannel) == typeof(IRequestSessionChannel)
            return (TChannel)(object)new ReliableRequestSessionChannel(this, this, binder, this.faultHelper, channelParameters, WsrmUtilities.NextSequenceId());
        }
    }
}