电脑故障

位置:IT落伍者 >> 电脑故障 >> 浏览文章

WCF中通过Dispose有效实现重用


发布日期:2020/7/29
 

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

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

var myClient = new MyClient();

try

{

//其他代码

myClientClose();

}

catch (CommunicationException)

{

myClientAbort();

}

catch (TimeoutException)

{

myClientAbort();

}

catch (Exception)

{

myClientAbort();

throw;

}

在最后增加对Exception异常的捕获很有必要因为我们不知道Close()方法会否抛出某些不可预知的异常例如 OutOfMemoryException等新闻中提到Steve Smith的方法其实就是对这段冗长代码的封装封装方式是采用扩展方法扩展的类型为ICommunicationObject这是因为所有的客户端对象都实现了ICommunicationObject接口

以下是Steve Smith的扩展方法代码

public static class Extensions

{

public static void CloseConnection(this ICommunicationObject myServiceClient)

{

if (myServiceClientState != CommunicationStateOpened)

{

return;

}

try

{

myServiceClientClose();

}

catch (CommunicationException ex)

{

DebugPrint(exToString());

myServiceClientAbort();

}

catch (TimeoutException ex)

{

DebugPrint(exToString());

myServiceClientAbort();

}

catch (Exception ex)

{

DebugPrint(exToString());

myServiceClientAbort();

throw;

}

}

}

利用该扩展方法在本应调用Close()方法的地方代替为CloseConnection()方法就可以避免写冗长的catch代码而使用 Lambda表达式的方式可以说是独辟蹊径使用起来与using语法大致接近实现方法是定义一个静态方法并接受一个 ICommunicationObject对象与Action委托

public class Util

{

public static void Using(T client Action action)

where T : ICommunicationObject

{

try

{

action(client);

clientClose();

}

catch (CommunicationException)

{

clientAbort();

}

catch (TimeoutException)

{

clientAbort();

}

catch (Exception)

{

clientAbort();

throw;

}

}

}

使用时可以将原本的客户端代码作为Action委托的Lambda表达式传递给Using方法中

UtilUsing(new MyClient() client =>

{

clientSomeWCFOperation();

//其他代码;

});

还有一种方法是定义一个自己的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(TimeSpanFromSeconds());

}

public void Close(TimeSpan span)

{

if (m_innerFactory != null)

{

if (m_innerFactoryState != CommunicationStateOpened)

{

return;

}

try

{

m_innerFactoryClose(span);

}

catch (CommunicationException)

{

m_innerFactoryAbort();

}

catch (TimeOutException)

{

m_innerFactoryAbort();

}

catch (Exception)

{

m_innerFactoryAbort();

throw;

}

}

}

private void Dispose(booling disposing)

{

if (disposing)

{

Close();

}

}

void IDisposableDispose()

{

Dispose(true);

GCSuppressFinalize(this);

}

}

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

上一篇:string、Empty和null三者的区别

下一篇:通过Cache实现通用的配置管理