WCF 异常(原创:灰灰虫的家http://hi.baidu.com/grayworm)
1.在WCF中異常機制特點:
??? a.當一個客戶端調用WCF服務產生異常后,只會導致當前調用結束,它并不影響其它客戶端對該WCF的調用,WCF仍然可以為其它客戶端繼續服務。
??? b.WCF產生的異常對象是CLR中的對象類型,而WCF客戶端卻不一定是.NET,可能是Java或PHP等。所以WCF服務不能向客戶端返回CLR異常對象。
下面看一段代碼:
服務端代碼:
??? [ServiceContract]
??? public interface ITestFault
??? {
??????? [OperationContract]
??????? int TestMethod(int num);
??? }
??? public class TestFault:ITestFault
??? {
?????? //這個方法接收一個整型的數值,然后把該值作為除數進行運算,并返回運算結果
??????? public int TestMethod(int num)
??????? {
??????????? return 100 / num;
??????? }
??? }
客戶端代碼:
?? public static void Main(string[] args)
??? {
??????? SRTestFault.TestFaultClient client = new Client.SRTestFault.TestFaultClient();
??????? client.Open();
??????? while (true)
??????? {
??????????? string str = Console.ReadLine();
??????????? int num = int.Parse(str);
??????????? try
??????????? {
??????????????? int result = client.TestMethod(num);
??????????????? Console.ForegroundColor = ConsoleColor.Cyan;
??????????????? Console.WriteLine(DateTime.Now.ToString() + "得到運算結果:" + result);
??????????? }
??????????? catch (Exception ex)
??????????? {
??????????????? Console.ForegroundColor = ConsoleColor.Red;
??????????????? Console.WriteLine(DateTime.Now.ToString() + "產生異常:" + ex.Message);
??????????? }
??????????? finally
??????????? {
??????????????? Console.ResetColor();
??????????? }
??????? }
??????? client.Close();
??? }
運行結果:
《圖1》
我們啟動了兩個客戶端,藍色字代表運行正常,紅色字代表運行出錯。
“客戶端一”在接收0的時候,會在服務端產生除數為0的異常,從圖中顯示的異常信息我們可以看到到:服務端的異常對象并沒有傳遞到客戶端,客戶端不知道服務端產生什么樣的異常。并且,一旦產生異常后,該客戶端與服務端的信道就會被中斷無法再進行通信。
雖然“客戶端一”與服務端的通信信道被中斷了,但服務端并沒有因為異常而停止運行。我們可以看到“客戶端二”中仍然可以與服務端進行通信。
2.WCF異常的分類:
??? a.通信錯誤,諸如網絡錯誤,地址錯誤,服務器沒有啟動等等。客戶端表現為Communication Exception。
??? b.狀態異常,代理已經關閉,或者通道Fault,等問題,這個比較常見。一般通道閑置時間過久,通道會出現這個狀態錯誤的問題。安全驗證失敗也會導致這個錯誤。
??? c.服務異常,服務調用時拋出的異常,這個服務內部異常會序列化傳遞給客戶端,被客戶端捕獲。
???
3.WCF異常與實例的關系:
??? a.Pre-Call實例模型: 服務實例被釋放,客戶端拋出 FaultException,產生異常的信道會被中斷,相應的客戶端代理對象無法繼續使用,只能關閉。不影響其它客戶端對服務的調用。
??? b.Pre-Session實例模型:服務實例被釋放,會話終止。客戶端拋出 FaultException,產生異常的信道會被中斷,相應的客戶端代理對象無法繼續使用,只能關閉。不影響其它客戶端對服務的調用。
?? c.Singleton實例模型:服務實例依舊運行。客戶端拋出 FaultException,產生異常的信道會被中斷,相應的客戶端代理對象無法繼續使用,只能關閉。不影響其它客戶端對服務的調用。
二、服務端返回異常的詳細信息
默認情況下,服務端產生運行異常后,并不會把異常的運行時信息傳遞到客戶端。我們在客戶端所得到的只是“由于內部錯誤,服務器無法處理請求”這樣的錯誤提示。這樣雖然能夠有效地保護好服務器的內部信息,但也為我們客戶端編程造成了很大的不方便。如何把服務端的錯誤信息傳遞到客戶端是我們這篇文章中主要要解決的問題,下面我們用最簡單的方法把服務端的異常信息發送到客戶端。
1.使用ServiceBehavior特性向客戶端傳遞異常信息。
把服務聲明為[ServiceBehavior(IncludeExceptionDetailInFaults=true)],其中的IncludeExceptionDetailInFaults=true代表向客戶端發送異常的詳細信息
服務端代碼:
??? [ServiceContract]
??? public interface ITestFault
??? {
??????? [OperationContract]
??????? int TestMethod(int num);
??? }
??? [ServiceBehavior(IncludeExceptionDetailInFaults=true)]
??? public class TestFault:ITestFault
??? {
??????? public int TestMethod(int num)
??????? {
??????????? return 100 / num;
??????? }
??? }
客戶端代碼保持不變。
運行結果:
《圖2》
2.使用配置文件中的serviceDebug配置節向客戶端傳遞異常信息。
除了可以使用ServiceBehavior把服務端信息傳遞到客戶端外,我們還可以修改Host的配置文件的serviceDebug配置節來向客戶端傳遞異常信息。
這種方式我們可以保持服務端代碼與客戶端代碼不作任何修改。只修改App.Config文件,如圖:
《圖3》
《圖4》
運行結果:
《圖2》
這種兩種方式可以很簡單地把服務端的錯誤信息傳送到客戶端,但他們也有兩個很大的缺陷:
1.會把服務端敏感的信息直接暴露給客戶端,如:數據庫的用戶名、服務器堆棧信息等。有些信息可能被人惡意利用,來對服務端進行攻擊。
2.客戶端雖然把服務端產生的異常信息獲取到了,但是客戶端與服務端的信道會被破壞,導致客戶端代理無法再與服務端通信,而只能關閉。
《圖5》
(原創:灰灰蟲的家http://hi.baidu.com/grayworm)
三、使用FaultException拋出簡單異常
在WCF服務中我們可以使用FaultException以標準Soap方式向客戶端傳遞簡單Fault信息。
在研究FaultException之前我們先來看一下標準Soap格式的Fault
《圖6》
從上面的圖中我們可以看出一個SoapFault包含Code和Reason。
Code:Soap錯誤的代碼;
Reason:Soap錯誤的原因,即錯誤信息;
FaultException常用構造函數:
public FaultException();
public FaultException(FaultReason reason);
public FaultException(string reason);
public FaultException(FaultReason reason,FaultCode code);
public FaultException(string reason,FaultCode code);
下面我們把上面的例子修改一下,WCF服務用FaultException向客戶端拋出錯誤信息。
服務端代碼:
??? [ServiceContract]
??? public interface ITestFault
??? {
??????? [OperationContract]
??????? int TestMethod(int num);
??? }
??? public class TestFault:ITestFault
??? {
??????? public int TestMethod(int num)
??????? {
??????????? int returnValue = 0;
??????????? try
??????????? {
??????????????? returnValue = 100 / num;
??????????? }
??????????? catch (Exception ex)
??????????? {
??????????????? FaultException fault = null;
??????????????? if (ex is DivideByZeroException)
??????????????? {
??????????????????? fault = new FaultException(new FaultReason("產生了除0的異常"), new FaultCode("Error:ox001"));
??????????????? }
??????????????? else
??????????????? {
??????????????????? fault = new FaultException(ex.Message);
??????????????? }
??????????????? throw fault;
??????????? }
??????????? return returnValue;
??????? }
??? }
??? 在服務端代碼我們使用了try-catch語句塊把產生的異常包裝成FaultException對象,拋向客戶端
客戶端代碼:
??? SRTestFault.TestFaultClient client = new Client.SRTestFault.TestFaultClient();
??? client.Open();
??? while (true)
??? {
??????? string str = Console.ReadLine();
??????? int num = int.Parse(str);
??????? try
??????? {
??????????? int result = client.TestMethod(num);
??????????? Console.ForegroundColor = ConsoleColor.Cyan;
??????????? Console.WriteLine(DateTime.Now.ToString() + "得到運算結果:" + result);
??????? }
??????? catch (FaultException ex)
??????? {
??????????? Console.ForegroundColor = ConsoleColor.Red;
??????????? Console.WriteLine(DateTime.Now.ToString() + "產生異常:錯誤代號-" + ex.Code.Name+",錯誤原因-" + ex.Reason);
??????? }
??????? catch(Exception ex)
??????? {
??????????? Console.ForegroundColor = ConsoleColor.Red;
??????????? Console.WriteLine(DateTime.Now.ToString() + "產生異常:" + ex.Message);
??????? }
??????? finally
??????? {
??????????? Console.ResetColor();
??????? }
??? }
??? //client.Close();
??? 在客戶端代碼中,我們也使用了try-catch-finally語句塊對服務端返回的錯誤信息進行捕捉,并顯示在界面上。
???
運行結果:
《圖7》
從圖中可以看出,我們把服務器端產生的錯誤捕獲出來,并顯示在界面上;但客戶端與服務端的信道并沒有被破壞,我們仍可以繼續向服務端發起新的調用。
優點:
??? 1.把服務端異常信息封裝成標準的Soap錯誤格式,通過Http傳遞,在客戶端可以得到服務端返回標準Soap錯誤,并從中取得出服務端異常信息。
??? 2.服務端拋出FaultException后,并不會破壞客戶端與服務端的信道,客戶端仍可以通過此信道向服務端發出調用。
缺點:只能向客戶端返回簡單的錯誤。
?
轉載于:https://www.cnblogs.com/LittleMobile/archive/2010/07/05/1771396.html
總結
以上是生活随笔為你收集整理的WCF 异常(原创:灰灰虫的家http://hi.baidu.com/grayworm)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: fatal error C1071: u
- 下一篇: 几大出版社