WCFは長い接続を実現する


WCFのメカニズムのため、接続プールは接続が確立された一定時間後にタイムアウトし、タイムアウト時間が非常に長く設定されていても、サービス側システムによってアクティブに回収される可能性があります.前にプロジェクトをしていたときにこの問題にぶつかったので、プロジェクトでは長い接続を採用し、接続プールを自動的に管理し、接続がタイムアウトした後、自動的に再構築し、セッションを維持することを考慮し、ビジネス層で接続タイムアウトの問題を処理する必要はありません.具体的には、プログラムの起動時に、まず長い接続を使用する必要がある接続を長い接続コンテナに入れ、接続の最大数を設定し、使用時に使用接続をポーリングし、使用時に異常をキャプチャした場合、自動的に次の接続に切り替え、前の接続を再構築することを考えています.コードは次のとおりです.
AliveConnectionクラス機能は、接続を保持し、具体的にはWCF呼び出しを実行し、接続が使用できないことを検出したときに再構築することです.

 class AliveConnection where T : System.ServiceModel.ICommunicationObject, new()
    {
        private string _endpointConfigName = string.Empty;
        private T _instance = default(T);
        /// 
        ///          ,     。       
        ///      ,              ,           :
        /// 1.          ;
        /// 2.         ;
        /// 
        public bool IsBusy { get; set; }

        internal AliveConnection(string endpointConfigName)
        {
            if (string.IsNullOrEmpty(endpointConfigName.Trim())) throw new ArgumentException("         。");
            _endpointConfigName = endpointConfigName;
            //_instance = CreateConnection();
        }

        internal bool Execute(Action expression)
        {
            try
            {
                Open();
                expression(_instance);
                return true;
            }
            catch (System.ServiceModel.CommunicationException e)
            {
                return false;
            }
        }

        internal bool Execute(Func expression,out TResult result)
        {
            result = default(TResult);
            try
            {
                Open();
                result = expression(_instance);
                return true;
            }
            catch (System.ServiceModel.CommunicationException e)
            {
                return false;
            }
        }

        private void Open()
        {
            if (_instance == null)//      
            {
                _instance = CreateConnection();
                _instance.Faulted += Faulted;
            }
            if (_instance.State != System.ServiceModel.CommunicationState.Opened)
                _instance.Open();
        }

        private void Faulted(object sender, EventArgs e)
        {
            lock (_instance)
            {
                IsBusy = true;
                //            
                _instance = CreateConnection();
            }
        }

        private T CreateConnection()
        {
            try
            {
                var instance = (T)Activator.CreateInstance(typeof(T), _endpointConfigName);
                IsBusy = false;
                return instance;
            }
            catch (Exception e)
            {
                IsBusy = true;
                RetryWhenFailed();
                throw new Exception("      ,           。", e);
            }
        }
        //                
        private void RetryWhenFailed()
        {
            int retryTimes = 0;
            Task.Factory.StartNew(() =>
            {
                while (true)
                {
                    //      ,      ,    ,        60 ,         
                    try
                    {
                        retryTimes++;
                        _instance = (T)Activator.CreateInstance(typeof(T), _endpointConfigName);
                        IsBusy = false;
                        break;
                    }
                    catch
                    {
                        int sleepMillionSeconds = retryTimes * 5 * 1000;
                        sleepMillionSeconds = sleepMillionSeconds > 60 * 1000 ? 60 * 1000 : sleepMillionSeconds;
                        System.Threading.Thread.Sleep(sleepMillionSeconds);
                        continue;
                    }
                }
            });
        }
    }

また、接続の初期化を行い、ポーリングを行い、実行する関数を暴露するクラスが必要です.
/// 
    /// WCF     
    /// 
    ///     WCF    
    public class AliveConnectionContainer
        where T : System.ServiceModel.ICommunicationObject, new()
    {
        #region fields
        private List> _connections = null;//    
        private int _currentConnectionIndex = 0;//          
        #endregion

        #region Octor
        /// 
        ///          ,     。            ,          ,            。
        /// 
        ///          
        ///           ,       bind name
        ///          ,     ,      ,      
        public AliveConnectionContainer(int maxConnection, params string[] endpointConfigNames)
        {
            _connections = new List>(maxConnection);

            int tmpIndex = 0;
            for (int index = 0; index < maxConnection; index++)
            {
                if (tmpIndex >= endpointConfigNames.Count()) tmpIndex = 0;
                _connections.Add(new AliveConnection(endpointConfigNames[tmpIndex]));
            }
        }
        #endregion

        #region public method
        /// 
        ///       ,             
        /// 
        ///          
        public void Execute(Action expression)
        {
            Func executeExpression = () => Instance.Execute(expression);
            Execute(executeExpression);
        }    
        /// 
        ///       ,             
        /// 
        ///          
        public TResult Execute(Func expression)
        {
            TResult result = default(TResult);
            Func executeExpression = () => Instance.Execute(expression,out result);
            Execute(executeExpression);
            return result;
        }

        private void Execute(Func expression)
        {
            bool success = false;
            int failedCount = 0;
            try
            {
                while (true)
                {
                    success = expression();
                    if (!success) failedCount++;
                    else break;

                    if (failedCount >= _connections.Count) throw new Exception("       ,         。");
                }
            }
            catch (Exception e)
            {
                throw new Exception("  WCF      。", e);
            }
        }

        #endregion

        #region private method
        private AliveConnection Instance
        {
            get
            {
                if (_connections == null || _connections.Count == 0) throw new Exception("       ,      。");
                AliveConnection result;
                while (!(result = GetInstance()).IsBusy) break;//           
                return result;
            }
        }

        private AliveConnection GetInstance()
        {
            if (_currentConnectionIndex >= _connections.Count) _currentConnectionIndex = 0;
            return _connections[_currentConnectionIndex++];
        }
        #endregion
    }

静的クラスを使用して、グローバルWCF接続の登録と取得を行います.
/// 
    ///          
    /// 
    /// 
    /// AliveConnectionManager.Register(endpoints,10);
    /// var client = AliveConnectionManager.Resolve();
    /// List movies;
    /// client.Execute(service => movies = service.GetMovies());
    /// 
    public static class AliveConnectionManager
    {
        private static Dictionary _container = new Dictionary();
        /// 
        ///           , app.config           ,     
        /// 
        ///     WCF     
        ///    
        ///         
        public static void Register(int maxConnection, params string[] endpointConfigNames)
            where T : System.ServiceModel.ICommunicationObject, new()
        {
            if (_container.ContainsKey(typeof(T))) throw new ArgumentException(string.Format("        {0}      。", typeof(T)));
            _container.Add(typeof(T), new AliveConnectionContainer(maxConnection, endpointConfigNames));
        }

        /// 
        ///      T      
        /// 
        ///     WCF     
        ///      T   
        public static AliveConnectionContainer Resolve() where T : System.ServiceModel.ICommunicationObject, new()
        {
            Type type = typeof(T);
            if (!_container.ContainsKey(type)) throw new ArgumentException(string.Format("       {0}      。", type));
            return _container[type] as AliveConnectionContainer;
        }
    }

サービス登録コード
 AliveConnectionManager.Register(endpoints,10);

 
コールサービス
var client = AliveConnectionManager.Resolve();
 List movies;
client.Execute(service => movies = service.GetMovies());

Serviceはクライアントで導入したWCFサービスです
変換元:https://www.cnblogs.com/flyingaway/p/8081302.html