熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> .NET編程 >> 正文

WCF中通過Dispose有效實現重用

2022-06-13   來源: .NET編程 

  本文將詳細介紹釋放客戶端資源(其中包括端口通道)和關閉連接的問題毫無疑問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的一次包裝從而有效地實現重用保證系統的安全性能與穩定性


From:http://tw.wingwit.com/Article/program/net/201311/13580.html
    推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.