先來說說SOAP消息中錯誤消息的包裝結構,一條SOAP錯誤消息的大致形式如下:
<s:Fault> <faultcode xmlns:a="me-cust-error">a:錯誤碼</faultcode> <faultstring xml:lang="zh-CN">錯誤內容。</faultstring>
……
</s:Fault>
首先是Fault元素,然后下面是錯誤消息相關聯的子元素。在上一篇爛文中,老周曾介紹過FaultReason,這個類用於包裝錯誤文本信息,並且支持多種語言。上面所展示的Fault元素中,faultstring子元素中的內容就是FaultReason類所指定的文本。
大伙伴們可能已經發現了,Fault元素下還有一個叫 faultcode 的子元素,它便是本文的主角,我們可以直接“望文生義”地將其翻譯為錯誤碼。錯誤碼是干嗎的?大伙應該知道 HTTP 中的錯誤代碼,如我們經常看到的 404- not found,道理也是一樣的, SOAP 消息中的錯誤碼就是用來對某一類錯誤進行標識的,通常用一些簡潔的短語,以便於識別。比如,一個錯誤命名為(錯誤碼)RPTooLow,你一看到這條錯誤,就知道是因為用戶的人品太差而導致操作失敗。
Fault code的命名就是一個字符串,你可以自己來取,當然應當取一些有意義的名字,不能只有你自己看得懂而別人摸不着頭腦,除非你的應用程序不打算對外公開錯誤信息。
在 WCF 中,可以用 FaultCode 類來定義錯誤碼,然后把該類的實例傳遞給 FaultException 的構造函數就 OK 了。
下面老周舉一個例子,假設有一個服務,它的功能是計算一個整數值的平方。其服務協定聲明如下。
[ServiceContract] public interface IDemo { [OperationContract] int Sqr(int n); }
然后實現這個服務協定。
class DemoService : IDemo { public int Sqr(int n) { if (n <= 0) { FaultCode code = new FaultCode("ArgErr", "me-cust-error"); FaultReason reason = new FaultReason("傳入的參數必須大於0。"); throw new FaultException(reason, code); } return n * n; } }
在上面的代碼中,注意 Sqr 方法,在方法里面對傳入的參數進行一下驗證,以確保值是大於0的。要是值不符合要求,就會拋出異常。
在拋出異常的時候,用 FaultCode 來定義一個錯誤碼,構造函數的第一個參數是錯誤碼的名字,第二個參數是XML命名空間,這個也是可以自己定義的。
下面,咱們調用一下這個服務,並故意傳一個錯誤的參數,以便可以捕捉到異常。
ChannelFactory<IDemo> fac = new ChannelFactory<IDemo>(binding, new EndpointAddress(svaddr)); fac.Endpoint.EndpointBehaviors.Add(new MyEndpointBehavior()); IDemo channel = fac.CreateChannel(); try { int res = channel.Sqr(-5); Console.WriteLine("計算結果:{0}", res); } catch (FaultException fex) { FaultReason reason = fex.Reason; FaultReasonText rtext = reason.GetMatchingTranslation(); FaultCode code = fex.Code; string errmsg = $"\n錯誤:{rtext.Text}\n錯誤代碼:{code.Namespace}:{code.Name}"; Console.WriteLine(errmsg); } finally { fac.Close(); }
這段代碼不是很復雜,應該不用我多解釋了,重點是捕捉的異常類型應當為 FaultException ,這個老周在上一篇文章中說過的。
運行的結果如下圖所示。
示例代碼下載地址:點擊下載
這篇文章老周是坐在屋頂上用 Surface 敲出來的。老周本來是拿着葫蘆絲到房頂上娛樂一下,吹奏了幾首曲子后,就打開 Surface 上上網,一時興起,就寫了本篇博客。