不要在using語句中呼叫WCF服務
阿新 • • 發佈:2019-02-03
如果你呼叫WCF服務時,像下面的程式碼這樣在using語句中進行呼叫,需要注意一個問題。
using (CnblogsWcfClient client = new CnblogsWcfClient())
{
client.Say("Hello, cnblogs.com!");
}
上面這段程式碼看上去沒問題,CnblogsWcfClient是一個自動生成的WCF客戶端代理,繼承自System.ServiceModel.ClientBase。using語句結束時,會呼叫ClientBase實現的System.IDisposable.Dispose介面,實際就是呼叫ClientBase的Close()方法。 用.NET Refector開啟C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.ServiceModel.dll,可以看到這樣的程式碼,見下圖:
不僅看上去沒問題,似乎就是沒問題。但是…問題就出在ClientBase.Close()上,Close()要關閉的是一個網路連線,如果這時網路連接出現問題,不能正常關閉會引發異常(ClientBase的Close方法就是這樣設計的,引發異常,而不是強制關閉),問題就來了。本來我們使用using的目的就是不管出現什麼狀況,即使天塌下來,也給我關閉掉;結果,關是關了,卻沒有閉,天還是塌下來了。
也許我們可以用“不可抗拒力”迴避這個問題,但程式設計師的天性是解決問題。程式碼中任何一個小問題都不能忽視,因為我們很難預料這個小問題會不會帶來大問題。
如何解決:
增加一個擴充套件方法,那麼就可以比較優雅的呼叫,而且不會出錯了。
客戶端呼叫程式碼如下:
string where = GetSearchSql();
new EnterpriseServiceClient().Using(enterpriseClient =>
{
this.winGridViewPager1.AllToExport = enterpriseClient.FindToDataTable(where);
});
/// <summary> /// WCF服務包裝類,避免使用Using等方式導致服務出錯的問題 /// </summary> public static class WcfExtensions { public static void Using<T>(this T client, Action<T> work) where T : ICommunicationObject { try { work(client); client.Close(); } catch (CommunicationException e) { client.Abort(); } catch (TimeoutException e) { client.Abort(); } catch (Exception e) { client.Abort(); throw; } } }