傳統 WCF 服務中,每個方法都需包裹 try-catch,導致業務代碼混雜異常處理邏輯,維護困難。本文展示如何用 IErrorHandler 實現集中式異常處理,讓服務代碼回歸純淨。
public string Div(int x, int y)
{
int result = 0;
try
{
result = x / y;
}
catch (DivideByZeroException ex)
{
throw ex;
}
return string.Format("{0}", result);
}
public string Div(int x, int y)
{
return string.Format("{0}", x / y); // 直接拋出異常,由框架統一處理
}
public class FaultErrorHandler : IErrorHandler
{
public bool HandleError(Exception error)
{
// 記錄日誌等橫切關注點
Console.WriteLine("Message:{0}, StackTrace:{1}", error.Message, error.StackTrace);
return true; // true 表示已處理,不再傳播
}
public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
{
// 將異常轉為 SOAP Fault 回傳客戶端
FaultException fe = new FaultException(
error.Message,
FaultCode.CreateReceiverFaultCode(error.Source, error.StackTrace)
);
MessageFault messageFault = fe.CreateMessageFault();
fault = Message.CreateMessage(version, messageFault, "https://www.microsoft.com/");
}
}
public sealed class ServiceErrorBehavior : BehaviorExtensionElement, IServiceBehavior
{
public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase) { }
public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase,
Collection endpoints, BindingParameterCollection parameters) { }
public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
{
IErrorHandler errorHandler = new FaultErrorHandler();
foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
channelDispatcher.ErrorHandlers.Add(errorHandler);
}
}
public override Type BehaviorType => typeof(ServiceErrorBehavior);
protected override object CreateBehavior() => new ServiceErrorBehavior();
}
<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="enforceGreetingFaults"
type="Common.ServiceErrorBehavior, Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
<serviceBehaviors>
<behavior name="WcfService.Service1Behavior">
<serviceMetadata httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true" />
<enforceGreetingFaults /> <!-- 關鍵:啟用自定義錯誤處理 -->
</behavior>
</serviceBehaviors>
</system.serviceModel>
type="Namespace.Class, Assembly, Version=..., Culture=neutral, PublicKeyToken=null",逗號後必須有一個空格,否則服務啟動失敗[FaultContract(typeof(YourFaultType))] 才能讓客戶端正確反序列化強型別異常true 表示異常已處理不再傳播;false 會繼續向上拋出透過 IErrorHandler + 自定義 BehaviorExtensionElement,實現 WCF 異常處理的「橫切關注點」分離。服務代碼專注業務邏輯,異常記錄、轉換、回傳統一由框架層完成,大幅提升代碼可維護性與一致性。