程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF服務調用中發生的異常及處理技巧

WCF服務調用中發生的異常及處理技巧

編輯:關於.NET

文章最後給出正確捕獲異常的捕獲順序。本次異常捕獲僅為介紹,部分為應用性功能,所以代碼和行文相對簡單,還介紹了在服務器端異常處理的一些技巧。

1、首先,我們創建一個簡單的計算器服務器和客戶端,如下:

點擊展開代碼

//服務器
[ServiceContract]
public interface ICalc
{
[OperationContract]
[FaultContract(typeof(GreentingError))]
string Div(int x, int y);
}
public class Calc : ServiceBase, ICalc
{
public string Div(int x, int y)
{string result = string.Empty;
try
{result = string.Format("result: {0}", x / y); } catch (DivideByZeroException ex)
{throw ex; }return result; }}
//客戶端
[ServiceContract]
public interface ICalc
{
[OperationContract]
[FaultContract(typeof(GreentingError))]
string Div(int x, int y);
}
public class CalcClient : ClientBase<ICalc>, ICalc
{ public string Div(int x, int y) {return base.Channel.Div(x, y); }}

好吧,我承認代碼相當的簡單,不過我喜歡簡潔的東西。

2、簡單的東西就是好,調用都簡單得多;我們來調用一下。

try
{
CalcClientcalcclient = new CalcClient();
string result =calcclient.Div(10, 0);
Console.WriteLine(result);
Console.ReadKey();
}
catch (TimeoutExceptionex) {throw ex; }
catch (FaultException<GreentingError> ex) {throw ex; }
catch (FaultExceptionex) {throw ex;
catch (System.ServiceModel.CommunicationException ex) {throw ex; }
catch (Exceptionex) {throw ex; }

3、當我們在調用服務的Div(int x,int y)方法並給對數y傳遞了值為0後,服務器端將會引發DivideByZeroException的異常,這在預料之中。這時候,

在客戶端的FaultException部分捕獲了這個異常。

4、沒問題,我們再在服務器代碼中手動拋出FaultException異常。

catch (DivideByZeroException ex)
{FaultException exception = new FaultException(ex.Message); throw exception;}

這時候發現,還是FaultException捕獲了這個異常,為何?

5、再做一個測試。

在服務加入這句代碼:System.Threading.Thread.Sleep(70000);使得服務超時。

這回終於是TimeOutException捕獲了服務器的異常,那麼我們就要問了,FaultException< GreentingError>何時會捕獲異常呢?答案是當服務器拋出FaultException< GreentingError>的時候,引用MSDN上的一段話(綠色部分):

如果偵聽器接收到操作協定中不期望或未指定的 SOAP 錯誤,將會引發 FaultException對象, 可以發送兩種類型的 SOAP 錯誤:已聲明的和未聲明的。 已聲明的 SOAP 錯誤是指其中的某個操作具有System.ServiceModel.FaultContractAttribute屬性(用於指定自定義 SOAP 錯誤類型)的錯誤。 未聲明的 SOAP 錯誤是在操作的協定中沒有指定的錯誤。這裡的“不期望或未指定的 SOAP 錯誤”是指未在服務操作中應用FaultContractAttribute包裝的自定義錯誤類型。

6、那麼何時會捕獲CommincationException異常呢?

MSDN上說是:應用程序處理在通信期間可能會引發的 CommunicationException 對象

好吧,為了引發這個異常,我們來作如下操作。首先在服務器關閉當前通道對象。

OperationContext.Current.Channel.Close();

很遺憾,客戶端並沒有捕獲到CommunicationException,而是捕獲到了TimeOutException異常!因為服務通道關閉後,並未發生異常,所以沒有返回消息到客戶端,客戶端在等待一定時間後,超時退出。

所以我們在關閉通道的同時指定一個TimeSpan。這樣可以讓調用立即返回,當然,還可以通過Channel.Abort來完成調用返回。

OperationContext.Current.Channel.Close(new TimeSpan(5000));

在調用了IContextChannel的Close方法的同時,指定在超時前必須完成發送操作的時間,這樣可以使得消息在指定時間內立即返回,而不必等到服務調用超時,否則到時客戶端必將引發TimeOutException異常,而不是 CommunicationException異常。

7、補救措施

同時,為了在服務出現異常時我們可以采取一些補救的措施,我們新建了一個抽象類ServiceBase,並使得Calc服務實現類繼承自它,這樣我們就可以在服務各種狀態轉換中取得控制權。ServiceBase類如下:

public abstract partial class ServiceBase
{
private IContextChannel channel = null;
protected ServiceBase()
{
channel = OperationContext.Current.Channel;
channel.Opening += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ });
channel.Opened += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ });
channel.Closing += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ });
channel.Closed += new EventHandler(delegate(object sender, EventArgs e) { Abort(); });
channel.Faulted += new EventHandler(delegate(object sender, EventArgs e) { Abort(); });
}
void Open() {/* TO DO*/ }
void Close() { /* TO DO*/}
void Abort() { channel.Abort(); }
}

從上面的代碼中可以看出,在服務通道關閉以後,我們立即將服務中止,讓消息立即返回,這時候即使在操作中關閉了服務而又未指定超時完成的時間,調用依然可以立即返回。

這次客戶端總算捕獲到了CommunicationException異常,見下圖:

為何會這樣?

8、讓我們來看一下CommunicationException的繼承層次,從中我們可以得到啟示。

8.1、首先是FaultException<TDetail>的繼承層次。

8.2、再次是TimeOutException的繼承層次。

9、從上圖中可以看出,TimeOutException和 CommunicationException均繼承自SystemException類,而FaultException繼承自 CommunicationException,最後是FaultException<TDetail>繼承自FaultException 類。

10、最後我們得出,在客戶端正確的捕獲異常的順序應該是:

TimeOutException> FaultException<TDetail> > FaultException >CommunicationException > Exception。在這裡強烈建議開發人員拋出和捕獲FaultException<TDetail>類型的異常。

出處:http://www.cnblogs.com/viter/

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved