WCF 服務拋出的 .NET 例外無法直接序列化傳遞給客戶端。若服務直接 throw new DirectoryNotFoundException(...),客戶端 catch (DirectoryNotFoundException) 永不會命中,只能捕獲泛型 FaultException 或 Exception,且會導致通道進入 Faulted 狀態,後續呼叫拋出 CommunicationObjectFaultedException,服務實例(PerSession/Singleton)甚至被終結。
[FaultContract(typeof(DirectoryNotFoundException))]throw new FaultException<DirectoryNotFoundException>(
new DirectoryNotFoundException(),
new FaultReason($"Directory {homeDir} is not found."));
catch (FaultException<DirectoryNotFoundException> ex) —— 可取得詳細錯誤資訊,通道保持開啟,服務實例存活,後續呼叫正常。在 [ServiceBehavior(IncludeExceptionDetailInFaults = true)] 或組態開啟,客戶端可捕獲非 FaultException 詳細資訊,但通道仍會錯誤,**嚴禁生產環境開啟**(洩露堆疊細節)。
適合不想在每個操作加 FaultContract、或需統一記錄日誌的場景。
IErrorHandler:ProvideFault() 將一般例外轉為 FaultException<T>;HandleError() 處理記錄日誌等副作用。IServiceBehavior,在 ApplyDispatchBehavior() 中將自身加入 ChannelDispatcher.ErrorHandlers。public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
if (error is DirectoryNotFoundException)
{
var fe = new FaultException<DirectoryNotFoundException>(
new DirectoryNotFoundException(), new FaultReason(error.Message));
fault = Message.CreateMessage(version, fe.CreateMessageFault(), fe.Action);
}
}
public void ApplyDispatchBehavior(ServiceDescription desc, ServiceHostBase host)
{
foreach (ChannelDispatcher d in host.ChannelDispatchers)
d.ErrorHandlers.Add(this);
}
此法下,服務拋出原生例外,客戶端仍能收到強型別 FaultException<T>,通道不中斷,服務實例不終結。