WCF入门(八)——异常处理2
從前文中我們了解到,對于服務器端拋出的異常,WCF框架會把它封裝成FaultException返回給客戶端。系統自己封裝的FaultException攜帶的信息往往不夠,為了通知客戶端更多異常信息,需要我們在代碼中主動拋出FaultException。
????public class Service1 : IService1
????{
????????public void ErrorTest()
????????{
????????????try
????????????{
????????????????throw new InvalidOperationException("異常測試");
????????????}
????????????catch (Exception e)
????????????{
????????????????throw new FaultException(e.Message);
????????????}
????????}
????}
這種方式需要在所有的接口都實現,一來麻煩,而來也增加了代碼的復雜度。實際上,既然WCF框架本身就提供了封裝異常的功能,我們如果接管這個異常封裝的過程,那么就可以以一種統一的方式封裝FaultException,即能重新封裝FaultException提供詳細的錯誤信息,又不用修改服務代碼。
實際上,WCF本身就提供了讓我們自己接管異常處理的接口IErrorHandler,關于的IErrorHandler處理方式和實現說明,請參看MSDN文章——IErrorHandler接口,我這里就不多介紹了,一個基本的方式如下:
????public class ErrorHandler : IErrorHandler
????{
????????public bool HandleError(Exception error)
????????{
????????????return false;
????????}
????????public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
????????{
????????????var ex = new FaultException(error.Message);
????????????var mf = ex.CreateMessageFault();
????????????fault = Message.CreateMessage(version, mf, ex.Action);
????????}
????}
在ProvideFault接口里面可以實現把代碼中的異常封裝成FaultException。
在這里只是實現了這個接口,還沒有地方調用,無法生效。要使用這個接口,還需要把它和ServiceBehavior關聯起來,在IServiceBehavior對象的ApplyDispatchBehavior中關聯ErrorHanlder,一般有兩種方式:
下面就分別介紹下這兩中實現方式:
代碼中顯示關聯
代碼中顯示關聯的方式比較簡單,直接在Service中實現IServiceBehavior接口即可。
????public class Service1 : IService1 ,IServiceBehavior
????{
????????public void ErrorTest()
????????{
????????????throw new InvalidOperationException("異常測試");
????????}
????????#region IServiceBehavior 成員
????????public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
????????{
????????}
????????public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
????????{
????????????var errorHanlder = new ErrorHandler();
????????????foreach (ChannelDispatcher chanDisp in serviceHostBase.ChannelDispatchers)
????????????{
????????????????chanDisp.ErrorHandlers.Add(errorHanlder);
????????????}
????????}
????????public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
????????{
????????}
????????#endregion
????}
這種方式比較簡單,但得Service的邏輯變得復雜化,另外也不夠靈活,我們通常更多的時候使用配置文件中關聯的形式。
配置文件中關聯
配置文件并不能直接處理IserviceBehavior對象,它只能處理BehaviorExtensionElement對象。因此這種方式下,需要實現三個接口。
這里之所以分為三個接口/類,主要是為了更加靈活,像前面IErrorHandler的和IServiceBehavior就可以在直接代碼中顯示關聯的方式中使用。
????class ServiceBehavior : IServiceBehavior
????{
????????public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
????????{
????????}
????????public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
????????{
????????????var errorHanlder = new ErrorHandler();
????????????foreach (ChannelDispatcher chanDisp in serviceHostBase.ChannelDispatchers)
????????????{
????????????????chanDisp.ErrorHandlers.Add(errorHanlder);
????????????}
????????}
????????public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
????????{
????????}
????}
????public class ErrorHandlerElement : System.ServiceModel.Configuration.BehaviorExtensionElement
????{
????????protected override object CreateBehavior()
????????{
????????????return new ServiceBehavior();
????????}
????????public override Type BehaviorType
????????{
????????????get
????????????{
????????????????return typeof(ServiceBehavior);
????????????}
????????}
????}
在實現時,也按照習慣自由實現幾個接口,并非一定要實現三個對象,我通常就通常將IServiceBehavior和IErrorHandler合并到一個對象中實現。
代碼實現后,然后就需要在config文件中使用ErrorHandlerElement了。主要增加如下兩個地方的配置:
? ??1. 在behaviorExtensions中增加剛才寫的ErrorHandlerElement ? ??<extensions>
? ??? ??<behaviorExtensions>
? ??? ??? ??<addname="errorHanlder" type="WcfService.ErrorHandlerElement, WcfService, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
? ??? ??</behaviorExtensions>
? ??</extensions>
? ??<serviceBehaviors>
? ??? ??<behavior name="">
? ??? ??? ??<errorHanlder />
? ??? ??</behavior>
? ??</serviceBehaviors>
配置好后,重新編譯運行,則就可以看到ErrorHanlder的效果了。
增強異常信息
通過上面的方法處理后,我們就可以一種通用的方式來封裝FaultException了,但由于這里是通用的方式,也存在通用方式的缺點:不能對具體異常提供細化的信息。
這個問題并不容易解決,要提供具體細化的異常信息,最靠譜的方法還是捕獲異常,封裝成FaultException<T>子類。
不過,在文章Simplifying WCF: Using Exceptions as Faults中提供了一個通用的的序列化異常的方法,將異常序列化后傳遞到客戶端,客戶端就可以直接以像捕獲本地異常那樣捕獲遠程異常了,而不用捕獲FaultException。
不過,這個方法也有一點問題,那就是要求客戶端也是.net語言實現的,否則其它的語言是無法反序列化CLR異常的,失去了語言無關的特性。
轉載于:https://www.cnblogs.com/TianFang/archive/2013/01/03/2842744.html
總結
以上是生活随笔為你收集整理的WCF入门(八)——异常处理2的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分享30个激励的非营利网站设计精美案例
- 下一篇: 获取网络状态ConnectivityMa