概述:
在實際的項目開發中,我們常常會處理各種各樣的異常,在代碼中不斷充斥著try{}catch{}finally{}語句塊,這些處理有些時候是不可缺少的,因為誰都沒有辦法保證自己寫的代碼無異常運行,外部環境造成了異常存在的可能性,但是我常常覺得,捕獲異常的語句塊經常把原本清晰的業務邏輯弄得七零八落的,當然,本篇的目的不是說異常捕獲可完全避免,但到少WCF可以讓我們稍微從異常處理中得到一點解脫。
1、首先來看常規的服務實現類在處理異常時的做法,下面是常規的捕獲了一個除數為0的異常。
常規異常捕獲
public string Div(int x,int y)
{
int result=0;
try
{
result = x / y;
}
catch (DivideByZeroException ex)
{
throw ex;
}
return string.Format("{0}",result);
}
2、再看看應用了IErrorHandler接口來處理異常後的代碼。
public string Div(int x,int y)
{
return string.Format("{0}",x/y);
}
有爽的感覺嗎?如果沒有,請仔細想想1000個方法中的異常處理。這就是WCF讓程序自己拋出異常並自行捕獲。
3、如何實現?
3.1、要達到上述的效果,我們需要自定義一類並實現IErrorHandler接口,代碼相當的簡單,如下:
public class FaultErrorHandler : IErrorHandler
{
#region IErrorHandler 成員
public bool HandleError(Exception error)
{
// TO DO 在這裡可以做日志記錄等。
Console.WriteLine("Message:{0},StackTrace:{1}",error.Message,error.StackTrace);
return true;
}
public void ProvideFault(Exception error,MessageVersion version,ref Message fault)
{
FaultException fe = new FaultException(error.Message,FaultCode.CreateReceiverFaultCode(error.Source,error.StackTrace));
MessageFault messagefault = fe.CreateMessageFault();
fault = Message.CreateMessage(version,messagefault,"http://www.microsoft.com/");
}
#endregion
}
只有十來行代碼,相當於我們以前的創建日志文件代碼。
3.2、為了可復用性,我們希望所有的服務都可以使用上面的這段代碼,那麼我們就必須要創建一個可以在配置文件中注冊的服務配置類,也十分的簡單,如下:
public sealed class ServiceErrorBehavior : BehaviorExtensionElement,IServiceBehavior
{
public void Validate(ServiceDescription description,ServiceHostBase serviceHostBase) { return; }
public void AddBindingParameters(ServiceDescription description,ServiceHostBase serviceHostBase,System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints,BindingParameterCollection parameters) { return; }
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 { get { return typeof(ServiceErrorBehavior); } }
protected override object CreateBehavior() { return new ServiceErrorBehavior(); }
}
上面的代碼也是十來行而已,相當的簡單。這段代碼的意思是說:為了可以在配置文件中注冊一個配置,我實現了 BehaviorExtensionElement類,並重寫了BehaviorExtensionElement的BehaviorType屬性和 CreateBehavior方法,因為在服務啟動時,服務主機會自動的獲取BehaviorType類型和通過CreateBehavior方法創建一個擴展配置節點。實現的IServiceBehavior接口是為了在服務分發通道中添加自定的異常處理程序,這樣,在服務發生異常時WCF服務就可以通過這個配置節點找到相應的ErrorHandler處理程序,並自動調用。
4、在配置文件中注冊自定義的擴展配置節,我們所需要做的工作只是把下面的幾行代碼copy到app.config中,並將其放在system.serviceModel節點下。
<extensions>
<behaviorExtensions>
<add name="enforceGreetingFaults" type="Common.ServiceErrorBehavior,Common,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null" />
</behaviorExtensions>
</extensions>
4.1、然後,再把上面的擴展配置加入到服務配置中,即把enforceGreetingFaults加入到這裡,綠色部分為上面的擴展節點名稱:
注冊擴展配置
<serviceBehaviors>
<behavior name="WcfService.Service1Behavior">
<serviceMetadata httpGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="true" />
<enforceGreetingFaults />
</behavior>
</serviceBehaviors>
5、最後客戶端一如既往的調用服務就OK了。
6、特別注意事項:在創建服務擴展節點也就是(behaviorExtensions)時,需要仔細檢查type="Common.ServiceErrorBehavior,Common,Version=1.0.0.0,Culture=neutral,PublicKeyToken=null"這一串,一定要記得“,”號後面要帶一個空格,切記是帶一個,既不能多也不能少,否則服務主機注冊失敗。
出處:http://www.cnblogs.com/viter/