我們在玩web編程的時候,可能你會不經意的見到一些http500的錯誤,我想你應該不會陌生的,原因你應該也知道,服務器異常嘛,
這時候clr會把這個未處理的異常拋給iis并且包裝成http500的錯誤返回到客戶端,就比如下面這樣。

從這張圖中,我故意輸入了xss字符,然后的然后,web程序自爆異常,其實我想表達的意思就是,雖然說web程序拋異常了,但不代表iis就
掛了,所以iis還是需要給客戶端做出反饋,這就有了http header,和body信息,同樣的道理,wcf的服務器異常機制也是這樣。。。service
拋出了異常,不代表console就掛了,console要做的事情就是把這個異常包裝起來丟給調用方,而wcf是怎么包裝的呢???就是用了這篇所
說的FaultException。。。
## 一:FaultException
1\. faultexception是干什么的?
剛才我也說了,這個異常就是wcf來包裝遠程錯誤的,具體的類含義就是表示“SOAP錯誤“,如果你夠細心的話,你還會發現到它有個屬性
叫Serializable,有了它,這個叼毛就可以序列化到Soap消息中,對伐???

2\. 如果挖出faultexception?
挖出這個exception的方法有很多,比如我來造一個“除以0”的異常,如下所示:
Service:
~~~
1 public class HomeService : IHomeService
2 {
3 public Student Get(string id)
4 {
5 //這里必然會拋出異常。。。
6 var result = Convert.ToInt32(id) / Convert.ToInt32("0");
7
8 return new Student() { ID = Convert.ToInt32(id), Name = "hxc", SNS = "001" };
9 }
10 }
~~~
Client:
~~~
1 public class Program1
2 {
3 static void Main(string[] args)
4 {
5 using (HomeServiceClient client = new HomeServiceClient())
6 {
7 try
8 {
9 var result = client.Get("1");
10 }
11 catch (Exception ex)
12 {
13
14 }
15 }
16 }
17 }
~~~

看到了沒有,雖然wcf的service已經拋出異常了,但是還是被clr用Faultexception包裝起來了,正如你看到了s:Fault節點,仔細往下看的話,
你還會看到faultcode,faultstring,detail等等屬性節點,那下面有個問題就來了,我們平時在Client端都習慣這么寫。
~~~
1 using (HomeServiceClient client = new HomeServiceClient())
2 {
3 try
4 {
5 var result = client.Get("1");
6 }
7 catch (Exception ex)
8 {
9 client.Abort();
10 }
11 }
~~~
但是這么寫有個什么問題呢???就是不管客戶端拋出什么異常,我們都習慣用基類異常Exception捕獲,但是wcf有一點非常惡心的就是,
它的異常信息非常的少,第一眼根本看不出個一二三,這是因為所有的異常你都用頂級的exception捕獲,自然你能知道的信息就非常少,
這也很正常,如果你想要更詳細的信息,你是不是應該在Client端寫上更具體的異常捕獲類呢???就比如你現在已經知道的FaultException
是因為服務器的錯誤都是由它處理的。

如果現在你按照上圖中所coding的那樣,你是不是對異常信息可以了解的更深,起碼你知道這個異常的拋出,絕逼是因為通道是正常的,只是
servcie拋出異常了而已。。。那你可能要問了,我這話的言外之意就是還有其他異常類也會捕獲wcf拋出的異常,對的,比如說你的信道出現
故障,這時候會拋出一個“通信異常(CommunicationException)”。
## 三:如何挖出“通信異常”
?挖出這個異常,也是很簡單的,現在我們需要使用”會話級別“的binding,比如說nettcpbinding,wshttpbinding,這里的話,我選擇
后者,因為是這樣的,第一次服務器拋異常以后,客戶端和服務器端通信信道就會關閉,如果你在客戶端不重新new一個client,那么這時候你
第二次再使用client的話,這個時候就會產生“信道故障“,拋出CommunicationException,而當你看到CommunicationException的時候,
你可以非常有自信的說,老子的wcf根本就沒有連接到service,而是在client端就被殺死了。。。下面我演示一下。


## 四:自定義FaultException
現在你應該知道了,只要是Servcie的Exception都會拋出 FaultException,對吧,而且你用Fiddler觀察的話,也看的出其中的faultcode
和faultstring貌似都不是很詳細,那我就有一個想法了,既然wcf會自己給我包裝個FaultException,那何不我自己就在發生異常的時候自己包
裝一個自定義的FaultException,然后我可以包裝一些我自己想要告訴客戶端的信息,這樣的話是不是靈活性非常的大呢???想法很不錯,wcf
也是恩準這么做的,下面我把service的get方法更改如下,在FaultException中自定義Reason,Code,Action等等自定義信息。
~~~
1 public class HomeService : IHomeService
2 {
3 public Student Get(string id)
4 {
5 try
6 {
7 //這里必然會拋出異常。。。
8 var result = Convert.ToInt32(id) / Convert.ToInt32("0");
9
10 return new Student() { ID = Convert.ToInt32(id), Name = "hxc", SNS = "001" };
11 }
12 catch (Exception ex)
13 {
14 var reason = new FaultReason("你這個戰斗力只有五的渣渣。。。 這么簡單的錯誤都出來了,搞個雞巴毛");
15
16 var code = new FaultCode("500");
17
18 var faultException = new FaultException(reason, code, "是Get這個王八蛋");
19
20 throw faultException;
21 }
22 }
23 }
~~~

好了,大概就說這么多了,我的目的也很簡單,在寫wcf的client的時候,盡量做到異常越具體越好,這樣方便我們盡可能快的排查問題,因為
wcf的異常信息真的太tmd坑爹了!!!減輕痛苦,從小做起~~~
- 第一天 三種Binding讓你KO80%的業務
- 第二天 告別煩惱的config配置
- 第三天 client如何知道server提供的功能清單
- 第四天 你一定要明白的通信單元Message
- 第五天 你需要了解的三個小技巧
- 第六天 你必須要了解的3種通信模式
- 第七天 Close和Abort到底該怎么用才對得起觀眾
- 第八天 對“綁定”的最后一點理解
- 第九天 高級玩法之自定義Behavior
- 第十天 學會用SvcConfigEditor來簡化配置
- 第十一天 如何對wcf進行全程監控
- 第十二天 說說wcf中的那幾種序列化
- 第十三天 用WCF來玩Rest
- 第十四天 一起聊聊FaultException
- 終結篇 那些你需要注意的坑