WCF的問題和Using語句塊

作者: Jonathan Allen  發布時間: 2011-01-18 14:46  閱讀: 1635 次  推薦: 0   原文鏈接   [收藏]  

  WCF客戶端不能用在Using語句塊中,因為它可能會拋出不可預知的異常。即使你捕獲了異常,仍有可能一直保持連接。讓我們來看看形成這一問題的歷史原因,并提出幾個補救措施。

  在.NET中,資源管理的基礎就是IDisposable和Using語句塊。除了CLR對象,.NET中一切對象均使用這些工具進行管理。因此,我們需要知道為何微軟對于WCF框架的資源管理如此一籌莫展。

  WCF客戶端的首要問題是Close/Dispose方法會拋出異常。這與框架設計指南以及IDisposable規約背道而馳,從而導致Dispose方法可以在Finally語句塊中被不安全的調用。

  更糟糕的是,只要不調用Abort,Close/Dispose方法就會一直保持連接。太多的連接打開就會帶來性能的問題,應用程序也會變得不夠穩定。

  在新聞組中,有關此問題的討論可以追溯到2006年,Brian McNamara介紹了這一設計缺陷的幕后故事

ICommunicationObject(它是 ServiceHost,ClientBase,IChannel,IChannelFactory與IChannelListener最終繼承的對象) 總是具有關閉對象的兩個方法:(a)Close,(b)Abort。按照字面的理解,如果希望主動關閉對象,則調用Close;若要強制關閉則調用 Abort。

因此,Close()方法會接收一個Timeout參數,并包括一個異步版本(因為它可能阻塞線程),而且Close()還會拋出異常。Close拋出的異常為CommunicationException(CommunicationObjectFaultedException是其子類)與TimeoutException。

相反,Abort()并不會阻塞線程(也不會拋出任何異常),因此沒有Timeout值,也并不包含異步版本。

這兩個概念從最初的Indigo一直沿用至今[譯注:所謂至今是指Brian發表帖子的時間2006年10月25日]。就目前而言一切正常。

最初的定義為ICommunicationObject : IDisposalbe。作為一個標記接口,我們認為它可以用于通知用戶在可能的時候即刻釋放對象。然而問題卻接踵而來。

從Beta 1版本開始,我們修改了Dispose(),讓其等同于Abort()方法。一部分原因是Dispose()應該完成最起碼的必要的對象清理工作。在Beta 1中,這可能算得上是我們的頭號麻煩了。用戶可以將它們的通道(channel)對象放在using()語句塊中,緩存中任何等待被取出的消息都可能會丟失。事務無法提交,會話可能得到告知收到(ACKed)的消息等。

鑒于用戶的反饋,在Beta 2中我們又修改了實現,讓Dispose()近似等于Close()。我們知道,異常的拋出是問題之所在(部分原因在這篇帖子中已經說明),因此我們試圖 讓Dispose變得更加“聰明”。那就是說,如果當前并非Opened狀態,就會在內部調用Abort()。這仍然存在一系列問題,最主要的是你無法從可靠性角度推斷系統。Dispose仍然會拋出異常,但并非總是會通知你某些事情發生錯誤。最終,我們決定將IDisposable從 ICommunicationObject中移走。經過幾番爭辯,IDisposable在ServiceHost和ClientBase中被保留了下 來,因為從理論上講,對于多數用戶而言Dispose拋出異常仍然是可以接受的,他們更偏向于使用using()的便利性,具有該標記接口就可以更及時地 清除對象。你可能主張(我們的一部分開發人員抱有同樣的態度):應該將它從這兩個類中移走,然而好也罷歹也罷,我們終究作出了選擇。對于這個問題,你永遠 都不可能達成一致,因此我們在SDK樣例中給出了最佳實踐,那就是遵循try{Close}/catch{Abort}范式。


  補救措施

  Steve Smith提出了CloseConnection擴展方法[譯注:原文并沒有給出CloseConnection擴展方法的帖子,你可以訪問IDisposable與WCF]。在Finally語句塊中可以調用該方法,而不是調用Close,它封裝了Close/Abort邏輯。

  新聞組的發帖人bog1978建議使用C# lambda以支持創建類似Using的結構。方法接收一個新的客戶端對象,以及一個匿名方法,該方法持有的代碼與正常使用using語句塊包含的代碼完全相同。

  最后,還有一個補救措施是Erwyn Van Der Meer定義的WCF服務代理輔助類。用戶可以創建它,而不是通常的代理類,它可以糾正在關閉連接時出現的問題。一旦創建,它就會自動構建實際的代理,然后通過只讀屬性暴露它。

  查看英文原文:The Problems with WCF and the Using Block

0
0
 
標簽:WCF
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()