WCF中的Dispose
在我翻譯的InfoQ新聞《WCF的問(wèn)題和Using語(yǔ)句塊》中提到了釋放客戶端資源(其中包括端口、通道)和關(guān)閉連接的問(wèn)題。新聞并沒(méi)有很深入地討論,所以我想再補(bǔ)充一些內(nèi)容。
毫無(wú)疑問(wèn),在.NET Framework中,一個(gè)資源(尤其是非托管資源)通常都需要實(shí)現(xiàn)IDisposable接口。一旦實(shí)現(xiàn)了該接口,我們就可以使用using語(yǔ)句來(lái)管理資源,這是最便捷的方式。但是,一旦在using語(yǔ)句中拋出了異常,就可能不會(huì)正確完成資源的回收,尤其是連接,很可能會(huì)一直打開,既占用了通道和端口,還可能出現(xiàn)資源的浪費(fèi),從而影響系統(tǒng)的性能和穩(wěn)定性。
微軟推薦的最佳實(shí)踐是拋棄using語(yǔ)句,轉(zhuǎn)而利用try/catch(/finally)語(yǔ)句。它要求在try語(yǔ)句中調(diào)用Close()方法,而在catch中調(diào)用Abort()方法。在新聞中已經(jīng)說(shuō)明了Close()與Abort()方法的區(qū)別,即后者可以強(qiáng)制地關(guān)閉客戶端,包括關(guān)閉客戶端連接,釋放資源。由于Close()方法可能會(huì)拋出CommunicationException和TimeoutException異常,通常的客戶端代碼應(yīng)該是這樣:
var myClient =?new?MyClient();try
{
????//其他代碼
??? myClient.Close();
}
catch?(CommunicationException)
{
??? myClient.Abort();
}
catch?(TimeoutException)
{
??? myClient.Abort();
}
catch?(Exception)
{
??? myClient.Abort();
????throw;
}
在最后增加對(duì)Exception異常的捕獲很有必要,因?yàn)槲覀儾恢繡lose()方法會(huì)否拋出某些不可預(yù)知的異常,例如OutOfMemoryException等。新聞中提到Steve Smith的方法其實(shí)就是對(duì)這段冗長(zhǎng)代碼的封裝,封裝方式是采用擴(kuò)展方法,擴(kuò)展的類型為ICommunicationObject。這是因?yàn)樗械目蛻舳藢?duì)象都實(shí)現(xiàn)了ICommunicationObject接口。以下是Steve Smith的擴(kuò)展方法代碼:
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;
????????}
????}
}
?利用該擴(kuò)展方法,在本應(yīng)調(diào)用Close()方法的地方,代替為CloseConnection()方法,就可以避免寫冗長(zhǎng)的catch代碼。而使用Lambda表達(dá)式的方式可以說(shuō)是獨(dú)辟蹊徑,使用起來(lái)與using語(yǔ)法大致接近。實(shí)現(xiàn)方法是定義一個(gè)靜態(tài)方法,并接受一個(gè)ICommunicationObject對(duì)象與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;
????????}
????}
}
?使用時(shí),可以將原本的客戶端代碼作為Action委托的Lambda表達(dá)式傳遞給Using方法中:
Util.Using(new?MyClient(), client =>????{
??????? client.SomeWCFOperation();
????????//其他代碼;
????});
?還有一種方法是定義一個(gè)自己的ChannelFactory,讓其實(shí)現(xiàn)IDisposable接口,并作為ChannelFactory的Wrapper類。在該類中定義Close()和Dispose()方法時(shí),考慮到異常拋出的情況,并在異常拋出時(shí)調(diào)用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);
????}
}
其實(shí),新聞中提到采用代理模式的方式與此實(shí)現(xiàn)相同。總之,萬(wàn)變不離其宗,所有替代方案的設(shè)計(jì)本質(zhì)都是對(duì)冗長(zhǎng)的try/catch/finally的一次包裝,從而有效地實(shí)現(xiàn)重用,保證系統(tǒng)的安全、性能與穩(wěn)定性。
本文轉(zhuǎn)自wayfarer51CTO博客,原文鏈接:http://blog.51cto.com/wayfarer/280084,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的WCF中的Dispose的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: vue2.x 在引用插件的时候,npm
- 下一篇: 外观、体验升级 HUAWEI WATC