zoukankan      html  css  js  c++  java
  • WCF中的Dispose

    在我翻译的InfoQ新闻《WCF的问题和Using语句块》中提到了释放客户端资源(其中包括端口、通道)和关闭连接的问题。新闻并没有很深入地讨论,所以我想再补充一些内容。

    毫 无疑问,在.NET Framework中,一个资源(尤其是非托管资源)通常都需要实现IDisposable接口。一旦实现了该接口,我们就可以使用using语句来管理 资源,这是最便捷的方式。但是,一旦在using语句中抛出了异常,就可能不会正确完成资源的回收,尤其是连接,很可能会一直打开,既占用了通道和端口, 还可能出现资源的浪费,从而影响系统的性能和稳定性。

    微软推荐的最佳实践是抛弃using语句,转而利用 try/catch(/finally)语句。它要求在try语句中调用Close()方法,而在catch中调用Abort()方法。在新闻中已经说明 了Close()与Abort()方法的区别,即后者可以强制地关闭客户端,包括关闭客户端连接,释放资源。由于Close()方法可能会抛出 CommunicationException和TimeoutException异常,通常的客户端代码应该是这样:
    var myClient = new MyClient();
    try
    {
        //其他代码
        myClient.Close();
    }
    catch (CommunicationException)
    {
        myClient.Abort();
    }
    catch (TimeoutException)
    {
        myClient.Abort();
    }
    catch (Exception)
    {
        myClient.Abort();
        throw;
    }

    在 最后增加对Exception异常的捕获很有必要,因为我们不知道Close()方法会否抛出某些不可预知的异常,例如 OutOfMemoryException等。新闻中提到Steve Smith的方法其实就是对这段冗长代码的封装,封装方式是采用扩展方法,扩展的类型为ICommunicationObject。这是因为所有的客户端 对象都实现了ICommunicationObject接口。以下是Steve Smith的扩展方法代码:
    public static class Extensions
    {
        public static void CloseConnection(this ICommunicationObject myServiceClient)
        {
            if (myServiceClient.State != CommunicationState.Opened)
            {
                return;
            }
            try
            {
                myServiceClient.Close();
            }
            catch (CommunicationException ex)
            {
                Debug.Print(ex.ToString());
                myServiceClient.Abort();
            }
            catch (TimeoutException ex)
            {
                Debug.Print(ex.ToString());
                myServiceClient.Abort();
            }
            catch (Exception ex)
            {
                Debug.Print(ex.ToString());
                myServiceClient.Abort();
                throw;
            }
        }
    }

    利 用该扩展方法,在本应调用Close()方法的地方,代替为CloseConnection()方法,就可以避免写冗长的catch代码。而使用 Lambda表达式的方式可以说是独辟蹊径,使用起来与using语法大致接近。实现方法是定义一个静态方法,并接受一个 ICommunicationObject对象与Action委托:
    public class Util
    {
        public static void Using<T>(T client, Action action)
            where T : ICommunicationObject
        {
            try
            {
                action(client);
                client.Close();
            }
            catch (CommunicationException)
            {
                client.Abort();
            }
            catch (TimeoutException)
            {
                client.Abort();
            }
            catch (Exception)
            {
                client.Abort();
                throw;
            }
        }
    }

    使用时,可以将原本的客户端代码作为Action委托的Lambda表达式传递给Using方法中:
    Util.Using(new MyClient(), client =>
        {
            client.SomeWCFOperation();
            //其他代码;
        });

    还 有一种方法是定义一个自己的ChannelFactory,让其实现IDisposable接口,并作为ChannelFactory的Wrapper 类。在该类中定义Close()和Dispose()方法时,考虑到异常抛出的情况,并在异常抛出时调用Abort()方法。这样我们就可以在using 中使用自定义的ChannelFactory类。例如:
    public class MyChannelFactory:IDisposable
    {
        private ChannelFactory m_innerFactory;
        public MyChannelFactory(ChannelFactory factory)
        {
            m_innerFactory = factory;
        }
        ~MyChannelFactory()
        {
            Dispose(false);
        }
        public void Close()
        {
            Close(TimeSpan.FromSeconds(10));
        }
        public void Close(TimeSpan span)
        {
            if (m_innerFactory != null)
            {
                if (m_innerFactory.State != CommunicationState.Opened)
                {
                    return;
                }
                try
                {
                    m_innerFactory.Close(span);
                }
                catch (CommunicationException)
                {
                    m_innerFactory.Abort();
                }
                catch (TimeOutException)
                {
                    m_innerFactory.Abort();
                }
                catch (Exception)
                {
                    m_innerFactory.Abort();
                    throw;
                }
            }
        }
        private void Dispose(booling disposing)
        {
            if (disposing)
            {
                Close();
            }
        }
        void IDisposable.Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }
    }

    其实,新闻中提到采用代理模式的方式与此实现相同。总之,万变不离其宗,所有替代方案的设计本质都是对冗长的try/catch/finally的一次包装,从而有效地实现重用,保证系统的安全、性能与稳定性。

  • 相关阅读:
    PAT 甲级 1115 Counting Nodes in a BST (30 分)
    PAT 甲级 1114 Family Property (25 分)
    PAT 甲级 1114 Family Property (25 分)
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
    Python Ethical Hacking
  • 原文地址:https://www.cnblogs.com/wayfarer/p/1410294.html
Copyright © 2011-2022 走看看