WCF基本異常處理模式[上篇]_第1頁
WCF基本異常處理模式[上篇]_第2頁
WCF基本異常處理模式[上篇]_第3頁
WCF基本異常處理模式[上篇]_第4頁
WCF基本異常處理模式[上篇]_第5頁
已閱讀5頁,還剩5頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領

文檔簡介

1、WCF基本異常處理模式上篇由于WCF采用.NET托管語言(C#和NET)作為其主要的編程語言,注定以了基于WCF的編程方式不可能很復雜。同時,WCF設計的一個目的就是提供基于非業(yè)務邏輯的通信實現(xiàn),為編程人員提供一套簡單易用的應用編程接口(API)。WCF編程模式的簡單性同樣體現(xiàn)在異常處理上面,本篇文章的主要目的就是對WCF基于異常處理的編程模式做一個簡單的介紹。 一、當異常從服務端拋出對于一個典型的WCF服務調(diào)用,我個人傾向于將潛在拋出的異常費為兩種類型:應用異常(Application Exception)和基礎結(jié)構(gòu)(Infrastructure Exception)。前者為應用級別,主要體

2、現(xiàn)為執(zhí)行某個服務操作的業(yè)務邏輯拋出的異常;而后者則是業(yè)務無關的,通過WCF本身的基礎架構(gòu)拋出,主要體現(xiàn)在對象的序列化、消息的處理、消息傳輸和消息的分發(fā)等等。在這里我們更多地關注與應用異常。 首先,我們在不做任何異常處理相關操作的情況下,看看如果在服務端執(zhí)行某個服務操作的過程中拋出異常后,客戶端會得到怎樣的結(jié)果。我們通過實例的形式來演示這中場景。處于簡單和易于理解考慮,我們照例沿用計算服務的例子。 我們照例采用典型的四層結(jié)構(gòu)(Contract、Service、Hosting和Client),具體的層次在VS解決方案的劃分如圖1所示: 圖1 異常拋出實例解決方案結(jié)構(gòu) 下面代碼片斷表示服務契約(IC

3、alculator)和服務類型(CalculatorService)的定義。為了簡潔,在服務契約接口中,我們僅僅定義了唯一一個用于進行兩個整數(shù)觸發(fā)預算的方法Divide。服務契約和服務類型類型分別定義在項目Contracts和Services中。 1: using System.ServiceModel; 2: namespace 3: 4: ServiceContract(Namespace = ) 5: public interface ICalculator 6: 7: OperationContract 8: int Divide(int x, int y); 9: 10: 1: us

4、ing 2: namespace 3: 4: public class CalculatorService : ICalculator 5: 6: public int Divide(int x, int y) 7: 8: return x / y; 9: 10: 11: 接下來是通過Console應用程序(Hosting項目)對上面定義的WCF服務(CalculatorService)進行寄宿(Host)的代碼和相關配置。 1: using System; 2: using System.ServiceModel; 3: using 4: namespace 5: 6: public cla

5、ss Program 7: 8: static void Main(string args) 9: 10: using (ServiceHost host = new ServiceHost(typeof(CalculatorService) 11: 12: 13: host.Open(); 14: Console.Read(); 15: 16: 17: 18: 1: xml version="1.0" encoding="utf-8" ?> 2: <configuration> 3: <system.serviceModel&g

6、t; 4: <services> 5: <service name 6: <endpoint address binding="wsHttpBinding" contract /> 7: service> 8: services> 9: system.serviceModel> 10: configuration>最后在代表客戶端的Console應用程序(Client項目)中對計算服務CalculatorService進行調(diào)用。相關的服務調(diào)用代碼和配置如下所示,為了讓服務端在執(zhí)行Divide操作的時候拋出異常,特意將第二

7、個參數(shù)設置為0,以便服務在進行除法運算的時候拋出System.DivideByZeroException異常。 1: using System; 2: using System.ServiceModel; 3: using 4: namespace 5: 6: class Program 7: 8: static void Main(string args) 9: 10: using (ChannelFactory channelFactory = new ChannelFactory( 11: "calculatorservice") 12: 13: ICalculato

8、r calculator = channelFactory.CreateChannel(); 14: using (calculator as IDisposable) 15: 16: int result = calculator.Divide(1, 0); 17: 18: 19: 20: 21: 1: xml version="1.0" encoding="utf-8" ?> 2: <configuration> 3: <system.serviceModel> 4: <client> 5: <endp

9、oint address 6: binding="wsHttpBinding" contract name="calculatorservice" /> 7: client> 8: system.serviceModel> 9: configuration>“由于內(nèi)部錯誤,服務器無法處理該請求。有關該錯誤的詳細信息,請打開服務器上的 IncludeExceptionDetailInFaults (從 ServiceBehaviorAttribute 或從 配置行為)以便將異常信息發(fā)送回客戶端,或在打開每個 Microsoft .N

10、ET Framework 3.0 SDK 文檔的跟蹤的同時檢查服務器跟蹤日志。” 圖2 客戶端捕獲從服務端拋出的異常 從上面的實例演示中,我們可以獲知WCF在默認情況下的異常處理行為:對于服務端拋出的異常(這里主要指應用異常),客戶端捕獲到的總一個具有相同異常消息的異常。由于異常類型和消息固定不變,對于服務的客戶端來說,直接通過捕獲到的異常相關的信息是無法確定服務端在執(zhí)行服務操作的時候遇到的具體的錯誤是什么。 WCF如此設計的一個主要的目的為了安全。原因很簡單,由于我們不能保證服務端直接拋出的異常不包含任何敏感信息,所以直接將服務端原始的異常信息暴露給客戶端(對于服務提供者來說,該客戶端可能使

11、一個不受信任或者部完全受信任的第三方)。 二、 異常細節(jié)的傳輸通過上面的介紹,我們已經(jīng)意識到了:在默認的情況下,如果異常(主要指應用異常)在執(zhí)行服務操作的過程中拋出,其真正的異常信息并不能被客戶端捕獲。實際上,服務端具體的異常細節(jié)信息僅限于服務端可見,并不會傳遞到客戶端。 然后,不論對于開發(fā)階段的調(diào)試,還是維護階段的糾錯、排錯,如果在客戶端調(diào)用某個服務操作后能夠很直接地獲取到從服務端拋出異常的所有細節(jié),這無疑是一件很有價值的事情。那么,WCF能夠做到這一點呢?答案是肯定的。 實際上,對于細心的讀者,看到客戶端捕獲的FaultException異常的消息,就能從中找到解決方案。消息中指出,如果試

12、圖得到服務端具體的錯誤信息,需要開啟IncludeExceptionDetailInFaults這么一個開關。具體來講,又具有兩種等效的方式:配置的方式和應用自定義特性(Custom Attribute)的方式。 通過在服務端的配置中,為寄宿的服務定義相應的服務行為(Service Behavior),并把serviceDebug配置項的includeExceptionDetailInFaults屬性設為True。具體配置如下所示: 1: xml version="1.0" encoding="utf-8" ?> 2: <configurat

13、ion> 3: <system.serviceModel> 4: <behaviors> 5: <serviceBehaviors> 6: <behavior name="serviceDebuBehavior"> 7: <serviceDebug includeExceptionDetailInFaults="true" /> 8: behavior> 9: serviceBehaviors> 10: behaviors> 11: <services> 12

14、: <service behaviorConfiguration="serviceDebuBehavior" name 13: <endpoint address binding="wsHttpBinding" contract /> 14: service> 15: services> 16: system.serviceModel> 17: configuration>大部分系統(tǒng)自定義服務行為都可以直接通過在服務類型上應用這么一個自定義特性一樣,includeExceptionDetailInFaults服務

15、調(diào)試(ServiceDebug)行為也不另外。在ServiceBehaviorAttribute中定義了一個IncludeExceptionDetailInFaults屬性,當我們將ServiceBehaviorAttribute特性應用到具體的服務類型上的時候,只需將此屬性設為true即可。 1: AttributeUsage(AttributeTargets.Class) 2: public sealed class ServiceBehaviorAttribute : Attribute, IServiceBehavior 3: 4: /其他成員 5: public bool Inclu

16、deExceptionDetailInFaults get; set; 6: 所以如果不采用上面的配置,在服務類型CalculatorService上面應用ServiceBehaviorAttribute特性,并進行如下的設置,也可以到達相同的效果。 1: using 2: using System.ServiceModel; 3: namespace 4: 5: ServiceBehavior(IncludeExceptionDetailInFaults = true) 6: public class CalculatorService : ICalculator 7: 8: /省略服務成員

17、 9: 10: 當IncludeExceptionDetailInFaults被開啟的ServiceDebug服務屬性通過上述兩種方式應用到我們例子中的服務CalculatorService的情況下,運行客戶端應用程序,將會捕獲包含有錯誤明細信息的異常,運行的結(jié)果如圖3所示: 圖3 客戶端捕獲到具有明細信息的異常 對于所有從服務端拋出的異常,只有FaultException和直接或間接繼承自FaultException的異常才能被序列化,并最終通過消息返回給服務的調(diào)用端。FaultException可以通過文本的形式保存相應的錯誤信息。FaultException在FaultException

18、現(xiàn)有的基礎上,增加了一個額外的特性:將錯誤信息通過一個具體的對象表示,其類型便是范型類型TDetail,該對象可以通過屬性Detail設置或者獲取。 1: Serializable 2: public class FaultException : FaultException 3: 4: / 其他成員 5: public FaultException(TDetail detail); 6: public TDetail Detail get; 7: 對于上面例子對應的場景,客戶端捕獲的異常類型實際上是FaultException< >,也就是說其具體的泛型類型參數(shù)為。Excepti

19、onDetail的定義如下: 1: DataContract 2: public class ExceptionDetail 3: 4: / 其他成員 5: public ExceptionDetail(Exception exception); 6:  7: DataMember 8: public string HelpLink get; private set; 9: DataMember 10: public ExceptionDetail InnerException get; private set; 11: DataMember 12: public string Me

20、ssage get; private set; 13: DataMember 14: public string StackTrace get; private set; 15: DataMember 16: public string Type get; private set; 17: ExceptionDetail是一個數(shù)據(jù)契約(Data Contract),也就意味ExceptionDetail是一個可以被DataContractSerializer進行序列化的對象。再仔細察看具體的屬性成員列表,我想很多讀者肯定有一種是曾相識的感覺:是不是和System.Exception的屬性成員定

21、義很相似。實際上,ExceptionDetail是WCF專門設計出來用于封裝服務端拋出的異常信息的,其個屬性HelpLink、InnerException和StackTrace各自和System.Exception的同名屬性向?qū)鴮傩訲ype表示異常的類型。 也就是說,對于應用了開啟IncludeExceptionDetailInFaults的ServiceDebug服務行為的WCF服務,在執(zhí)行服務操作拋出的異常信息,可以通過包含在客戶端捕獲的FaultException異常中的ExceptionDetail對象獲取。比如,在下面的代碼中,我修改了客戶端的代碼,將具體的錯誤信息輸出到控制臺

22、上: 1: using System; 2: using System.ServiceModel; 3: using 4: namespace 5: 6: class Program 7: 8: static void Main(string args) 9: 10: using (ChannelFactory channelFactory = new ChannelFactory( 11: "calculatorservice") 12: 13: ICalculator calculator = channelFactory.CreateChannel(); 14: us

23、ing (calculator as IDisposable) 15: 16: try 17: 18: int result = calculator.Divide(1, 0); 19: 20: catch (FaultException ex) 21: 22: Console.WriteLine("Message:0" 23: Console.WriteLine("Type:0" 24: Console.WriteLine("StackTrace:0" 25: Console.WriteLine("HelpLink:0" 26: (calcul

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論