我們在玩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坑爹了!!!減輕痛苦,從小做起~~~