File: System\ServiceModel\Channels\ChannelTracker.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.Collections.Generic;
    using System.Diagnostics;
    using System.Runtime;
    using System.ServiceModel;
    using System.ServiceModel.Diagnostics.Application;
 
    // Track channels and (optionally) associated state
    class ChannelTracker<TChannel, TState> : CommunicationObject
        where TChannel : IChannel
        where TState : class
    {
        Dictionary<TChannel, TState> receivers;
        EventHandler onInnerChannelClosed;
        EventHandler onInnerChannelFaulted;
 
        public ChannelTracker()
        {
            this.receivers = new Dictionary<TChannel, TState>();
            this.onInnerChannelClosed = new EventHandler(OnInnerChannelClosed);
            this.onInnerChannelFaulted = new EventHandler(OnInnerChannelFaulted);
        }
 
        public void Add(TChannel channel, TState channelReceiver)
        {
            bool abortChannel = false;
            lock (this.receivers)
            {
                if (this.State != CommunicationState.Opened)
                {
                    abortChannel = true;
                }
                else
                {
                    this.receivers.Add(channel, channelReceiver);
                }
            }
 
            if (abortChannel)
            {
                channel.Abort();
            }
        }
 
        public void PrepareChannel(TChannel channel)
        {
            channel.Faulted += this.onInnerChannelFaulted;
            channel.Closed += this.onInnerChannelClosed;
        }
 
        void OnInnerChannelFaulted(object sender, EventArgs e)
        {
            ((TChannel)sender).Abort();
        }
 
        void OnInnerChannelClosed(object sender, EventArgs e)
        {
            // remove the channel from our tracking dictionary
            TChannel channel = (TChannel)sender;
            this.Remove(channel);
            channel.Faulted -= this.onInnerChannelFaulted;
            channel.Closed -= this.onInnerChannelClosed;
        }
 
        public bool Remove(TChannel channel)
        {
            lock (this.receivers)
            {
                return this.receivers.Remove(channel);
            }
        }
 
        TChannel[] GetChannels()
        {
            lock (this.receivers)
            {
                TChannel[] channels = new TChannel[this.receivers.Keys.Count];
                this.receivers.Keys.CopyTo(channels, 0);
                this.receivers.Clear();
                return channels;
            }
        }
 
        protected override void OnAbort()
        {
            TChannel[] channels = GetChannels();
            for (int i = 0; i < channels.Length; i++)
            {
                channels[i].Abort();
            }
        }
 
        protected override void OnClose(TimeSpan timeout)
        {
            TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
            TChannel[] channels = GetChannels();
            for (int i = 0; i < channels.Length; i++)
            {
                bool success = false;
                try
                {
                    channels[i].Close(timeoutHelper.RemainingTime());
                    success = true;
                }
                catch (CommunicationException e)
                {
                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
                }
                catch (TimeoutException e)
                {
                    if (TD.CloseTimeoutIsEnabled())
                    {
                        TD.CloseTimeout(e.Message);
                    }
                    DiagnosticUtility.TraceHandledException(e, TraceEventType.Information);
                }
                finally
                {
                    if (!success)
                    {
                        channels[i].Abort();
                    }
                }
            }
        }
 
        protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        {
            TChannel[] channels = GetChannels();
            List<ICommunicationObject> collection = new List<ICommunicationObject>();
            for (int i = 0; i < channels.Length; i++)
            {
                collection.Add(channels[i]);
            }
 
            return new CloseCollectionAsyncResult(timeout, callback, state, collection);
        }
 
        protected override void OnEndClose(IAsyncResult result)
        {
            CloseCollectionAsyncResult.End(result);
        }
 
        protected override TimeSpan DefaultCloseTimeout
        {
            get { return ServiceDefaults.CloseTimeout; }
        }
 
        protected override TimeSpan DefaultOpenTimeout
        {
            get { return ServiceDefaults.OpenTimeout; }
        }
 
        protected override void OnOpen(TimeSpan timeout)
        {
        }
 
        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new CompletedAsyncResult(callback, state);
        }
 
        protected override void OnEndOpen(IAsyncResult result)
        {
            CompletedAsyncResult.End(result);
        }
    }
}