前言:
- 當我們打開WCF基礎客戶端通道(無論是通過顯式打開還是通過調用操作自動打開)、使用客戶端或通道對象調用操作,或關閉基礎客戶端通道時,都會在客戶端應用程序中出現異常。而我們知道WCF是基於網絡的通訊服務,錯誤異常也是要基於消息傳遞的,在WCF中提供了一個錯誤消息處理的類FaultException。接下來,我們看一下如何使用它在客戶端處理異常。
WCF異常類型:
- 意外異常:意外異常包括災難性故障(如 OutOfMemoryException)和編程錯誤(如 ArgumentNullException 或 InvalidOperationException)。通常沒有有效的方法來處理意外錯誤,所以通常不應在調用 WCF 客戶端通信方法時捕獲這些異常。
- 預期異常:預期異常包括 TimeoutException、CommunicationException 以及 CommunicationException 的任何派生類。這些異常表明通信過程中出現問題,該問題可以通過中止 WCF 客戶端並報告通信故障而得到安全的處理。因為外部因素可能導致任何應用程序中出現這些錯誤,所以正確的應用程序必須捕獲這些異常並在發生異常時進行恢復。
WCF客戶端異常處理示例:
- 工程結構如下圖所示:
- 工程結構說明:
- Service:類庫程序。定義和實現服務契約,包含Add()和Divide(),即加法和除法運算。
ICalculator.cs代碼如下:

using System.ServiceModel; using System.Collections.Generic; using System.Runtime.Serialization; namespace Service { [ServiceContract] public interface ICalculator { [OperationContract] int Add(int value1, int value2); [OperationContract] int Divide(int value1, int value2); } }
Calculator.cs代碼如下:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; namespace Service { public class Calculator:ICalculator { public int Add(int value1, int value2) { return value1 + value2; } public int Divide(int value1, int value2) { try { return value1 / value2; } catch(DivideByZeroException) { throw new FaultException("除數不能為0"); } } } }
2. Host:控制台應用程序。用來承載服務,添加對於Service程序集的引用后,實現以下代碼就可以承載服務。
Program.cs的代碼如下:

using System; using System.Collections.Generic; using System.Linq; using System.Text; using Service; using System.ServiceModel; namespace Host { class Program { static void Main(string[] args) { using (ServiceHost host = new ServiceHost(typeof(Calculator))) { host.Opened += delegate { Console.WriteLine("服務已經啟動,按任意鍵終止!"); }; host.Open(); Console.Read(); } } } }
App.config的代碼如下:

<?xml version="1.0"?> <configuration> <system.serviceModel> <services> <service name="Service.Calculator" behaviorConfiguration="mexBehavior"> <host> <baseAddresses> <add baseAddress="http://localhost:1234/Calculator/"/> </baseAddresses> </host> <endpoint address="" binding="wsHttpBinding" contract="Service.ICalculator" /> <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/> </service> </services> <behaviors> <serviceBehaviors> <behavior name="mexBehavior"> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="true"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
3. Client:控制台應用程序。將Host承載服務啟動后,客戶端程序添加對服務地址http://localhost:1234/Calculator/的引用,將命名空間設置為CalculatorServiceRef,
接下來我們就可以調用服務呢。Client的Program.cs代碼如下:
首先,我們將2、3的代碼注釋掉,只驗證服務異常拋出的結果,我們把Divide的除數設置為0,此時應該會捕獲到服務端拋出的異常信息。運行結果如下:
然后,我們把1、3注釋,只驗證通訊超時的異常拋出。我們將通道連接后的操作時間設置為非常小的一個值,那么服務端的運算肯定來不及處理,就會拋出超
時的異常信息。運行結果如下:
最后,我們將1、2注釋,只驗證通訊錯誤異常信息,我們在客戶端執行完Add()后,就把服務終止,即服務終止連接則會拋出通訊錯誤的異常信息,運行結果如下所示:
總結:
- 通過示例,我們可以看到,客戶端程序成功捕獲到了TimeoutException和CommunicationException以及自定義異常信息
- 如果發生預期異常,客戶端或許可以繼續使用,或許無法繼續使用。若要確定客戶端是否仍然可以使用,請檢查 State 屬性是否為 CommunicationState.Opened。
如果此屬性仍然處於打開狀態,則客戶端仍然可以使用。否則,則應中止客戶端並釋放對其的所有引用。具體參照代碼如下:
if (proxy.State == CommunicationState.Opened){ Console.WriteLine("CommunicationState is Opened"); }