本文系統闡述 WCF 三種異常處理模式(預設、詳細資訊、自定義錯誤合約)、適用場景、常見異常類型,並以實戰範例驗證各模式行為差異。適合已具備 WCF 基礎的開發人員。
FaultException,無堆疊追蹤、無業務錯誤細節兩種啟用方式:
<serviceDebug includeExceptionDetailInFaults="true" />[ServiceBehavior(IncludeExceptionDetailInFaults = true)]核心機制:SOAP Fault + FaultException<TDetail>
// 1. 定義資料合約
[DataContract]
public class ExceptionMsg {
[DataMember] public string Message { get; set; }
[DataMember] public string ErrorCode { get; set; }
}
// 2. 服務合約標註
[OperationContract]
[FaultContract(typeof(ExceptionMsg))]
int Divide(int x, int y);
// 3. 服務端拋出
throw new FaultException<ExceptionMsg>(
new ExceptionMsg { ErrorCode = "001", Message = "除數不能為0" },
new FaultReason("數學運算錯誤")
);
// 4. 客戶端捕獲
catch (FaultException<ExceptionMsg> ex) {
var detail = ex.Detail; // 強型別存取 ErrorCode、Message
}
| 異常類型 | 典型原因 | 代表類別 | 處理策略 |
|---|---|---|---|
| 通訊異常 | 服務未啟動、網路中斷、防火牆、繫結不匹配 | CommunicationException 及衍生類 |
重試機制、斷路器模式、記錄告警 |
| 狀態異常 | 存取已銷毀的服務實例(PerCall/PerSession 逾期) | ObjectDisposedException |
檢查 Proxy 狀態、重新建立 Proxy、調整逾時設定 |
| 服務異常 | 業務邏輯驗證失敗、資料庫錯誤、資源不足 | FaultException, FaultException<T> |
轉換為友善錯誤碼/訊息回傳客戶端、記錄完整日誌 |
當服務拋出 FaultException 時:
| InstanceContextMode | 服務實例 | 客戶端 Proxy |
|---|---|---|
| PerCall | 銷毀 | 失效(Faulted 狀態),需重建 |
| PerSession | 銷毀 | 失效,需重建 |
| Single | 存活 | 失效,需重建 |
關鍵結論:無論何種實例模式,客戶端 Proxy 一旦接收到 FaultException 即進入 Faulted 狀態,必須 Abort() 並重建。Single 模式下服務實例倖存,但該 Session 已中斷。

客戶端異常訊息不包含伺服器堆疊細節。

開啟 includeExceptionDetailInFaults 後,客戶端可見完整伺服器堆疊追蹤。

客戶端透過 FaultException<ExceptionMsg> 精準獲取 ErrorCode 與 Message。
使用 Trace Utility (SOAP Toolkit 3.0) 或 tcpTrace 攔截 SOAP 封包:
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode>s:Client</faultcode>
<faultstring xml:lang="zh-CN">The creator of this fault did not specify a Reason.</faultstring>
<detail>
<ExceptionMsg xmlns="https://schemas.datacontract.org/2004/07/Jillzhang.Wcf.ExContracts">
<ErrorCode>001</ErrorCode>
<Message>除數不能為0</Message>
</ExceptionMsg>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>






啟用「非使用者程式碼」除錯、設定符號伺服器、附加至服務宿主進程,實現無縫跨界除錯。
proxy.Abort(),切勿 Close()(會再次拋出異常)