Message和SOAP Fault
Message類型定義了一些用來創建表示SOAP Fault消息對象的工廠方法。SOAP Fault是SOAP消息的一種形式,它用來表示錯 誤信息。在SOAP規范(1.1 和1.2)對於消息體內容,並且某些時候,關於SOAP 消息頭塊的規定都存在差別。Message是對於SOAP消息的CLR抽象,Message可以 表示SOAP Fault,和表示一個SOAP消息一樣。本節會描述一些SOAP Fault的基本 概念和創建表示SOAP Fault消息的基本類型以及如何創建一個表示SOAP Fault的 Message實例。
SOAP Fault 剖析
SOAP Fault遵守SOAP規范(1.1 和1.2)。根本上,SOAP1.1 Fault包含一個SOAP body,body裡包裝了一個必須 的faultcode老徐備注2、faultstring元素,還有一個可選的faultactor和 faultdetail元素。為了避免重復敘述這些規范,你可以在這裡 http://www.w3.org/TR/soap11找到更多的可選擇元素的消息規范。在更高層次 上,faultcode表示一個標識符,接受者和發送者可以用來辨別錯誤SOAP1.1 規 范,定義了一個faultcode的小集合,但是程序可以定義自己使用的唯一的 faultcode。Faultstring表示一種人工可讀的 faultcode,它不是要給接收程序 (除非你想吧Faultstring顯示給用戶)。Faultcode是一個描述錯誤來源的URI 。
SOAP Fault 從SOAP 1.1到SOAP 1.2發生了很大的變化。因為SOAP 1.2 是建立在Infoset上的, SOAP 1.2 Fault本質上是由一個信息條目集合組成。除 了這些變化,SOAP Fault組成部分的名字也做了修改和擴展,以包含更多的描述 信息。SOAP 1.2規定SOAP Fault應該包含一個必須的Code和Reason(原因),一 個可選的Node、Role或Detail(詳細信息)。何時增加這些信息的詳細規定可以 在這裡查看:http://www.w3.org/TR/soap12-part1/#soapfault。通常來說, Code是發生錯誤的標識符,而且也允許使用子code表示更細粒度的信息。SOAP 1.2定義了一些Code,並且允許程序定義自己的Code。Reason便是人工可讀的錯 誤解釋信息。Node表示產生錯誤的消息參與者。Role信息表示的是SOAP錯誤產生 時,消息參與者的角色。Detail是給其它消息參與者准備的錯誤信息。
SOAP 1.1 和1.2 Fault,拋去他們的區別,在他們描述的信息類型上還 是很相似的。兩者都規定了錯誤代碼的標簽,人工可讀的錯誤描述信息,導致 SOAP Fault的消息參與者信息和錯誤的其它信息。為這目的,WCF定義了一個表 示SOAP 1.1和SOAP 1.2 FaultSystem.ServiceModel.Channels.MessageFault類 型。在我們學習如何表示SOAP 1.1 和SOAP 1.2描述的SOAP Fault之前,我們先 來看看MessageFault類型如何概括歸納SOAP Fault的。
MessageFault
The MessageFault type is a way to describe error information in a SOAP-version-agnostic manner. Keeping in mind that WCF has a highly layered architecture, the MessageFault type provides tremendous flexibility when processing SOAP messages and optionally generating exceptions.
MessageFault類型可以描述各種SOAP版本的錯 誤信息。記住WCF擁有更高層的架構,MessageFault類型在處理SOAP消息或者產 生異常的時候提供了巨大的靈活性。
創建一個 MessageFault對象 像 許多WCF裡的別的類型一樣,MessageFault是個定義了幾個工廠方法的抽象類型 。這些工廠方法接受表示SOAP Fault裡存儲信息的參數。此外MessageFault同樣 定義了接受產生SOAP Fault的消息參與者的標識作為參數。值得注意的是, MessageFault定義了一個工廠方法接受一個Message作為參數。這個方法在WCF接 收一個SOAP Fault Message,並需要傳遞這個錯誤信息到別的WCF基礎結構部分 進行處理的時候,非常有用。
System.ServiceModel.FaultCode類型表示 faultcode信息。這個類型定義了幾個工廠方法作為構造函數。所有的構建方法 雲系使用子code。FaultCode類型上的工廠方法,會自動產生發送者和接收者的 錯誤代碼(像SOAP 1.1 和SOAP 1.2定義的一樣)。
System.ServiceModel.FaultReason類型表示faultreason。最簡單的情 況,一個構造函數接受一個String字符串作為參數。String表示人工可讀的錯誤 信息。因為人說的語言不同(Microsoft .NET開發人員也不會說一個語言), FaultReason類型定義了構造函數和方法允許程序嵌入多種版本的String和適當 的基於不同文化的描述信息。
除了那一個MessageFault定義的工廠方法 ,其它的都接受一個FaultCode 和FaultReason類型作為參數。因此,這些類型 必須在MessageFault 創建之前實例化,除了從Message創建MessageFault。幾個 工廠方法也接受Object作為參數,這個表示額外的錯誤信息。對於 Message工廠 方法裡的Object參數,它們必須支持序列化(更多序列化的內容在第9章)。這 個參數的存在帶來一個問題,”我該使用什麼類型作為參數?”因為 System.Exception 是可序列化的,你或許會傳遞一個Exception參數。我強烈建 議你打消這個想法。我更願意自定義一個傳遞錯誤信息給其它消息參與者的類型 。正如我們將會在第9章看到的一樣,這給契約帶來了一個變化。
從 MessageFault創建Message
我們一旦創建了MessageFault,我們可以調 用Message上定義的別的工廠方法來創建一個Message。下面的代碼演示了如何使 用 FaultCode、FaultReason和Object去創建一個MessageFault,也包括如何從 MessageFault創建一個 Message。
static void Main() {
// create a Receiver Fault Code
FaultCode faultCode = FaultCode.CreateReceiverFaultCode("MyFaultCode","urn:MyNS");
// create a meaningful FaultReason
FaultReason faultReason = new FaultReason("The value must be > 10");
// create an object that represents the SOAP Fault detail
SomeFaultDetail faultDetail = new SomeFaultDetail("Contoso", "SomeApp");
// create a MessageFault
MessageFault messageFault = MessageFault.CreateFault(faultCode,faultReason,faultDetail);
// Build a Message from the MessageFault, passing the MessageVersion
CreateAndShowMessage(messageFault, MessageVersion.Soap11WSAddressing10);
CreateAndShowMessage (messageFault, MessageVersion.Soap12WSAddressing10);
}
private static void CreateAndShowMessage(MessageFault messageFault,
MessageVersion version) {
// actually create the Message object w/version info
Message message = Message.CreateMessage(version,
messageFault,
"urn:SomeFaultAction");
// show the contents of the Message
Console.WriteLine("{0}\n", message.ToString ());
}
// a serializable type for storing Fault detail information
[Serializable]
sealed class SomeFaultDetail {
String companyName;
String applicationName;
DateTime? dateOccurred;
internal SomeFaultDetail(String companyName, String applicationName) {
this.companyName = companyName;
this.applicationName = applicationName;
//this.dateOccurred = null;
this.dateOccurred = DateTime.Now;
}
}
運行代碼,產生以下結果:
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<a:Action s:mustUnderstand="1">
urn:SomeFaultAction
</a:Action>
</s:Header>
<s:Body>
<s:Fault>
<faultcode xmlns:a="urn:MyNS">a:MyFaultCode</faultcode>
<faultstring xml:lang="en-US">The value must be > 10</faultstring>
<detail>
<Program.SomeFaultDetail xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/MessageFaults">
<applicationName>SomeApp</applicationName>
<companyName>Contoso</companyName>
<dateOccurred>2006-06-14T12:34:44.52325- 04:00</dateOccurred>
</Program.SomeFaultDetail>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
<s:Envelope xmlns:a="http://www.w3.org/2005/08/addressing"
xmlns:s="http://www.w3.org/2003/05/soap-envelope">
<s:Header>
<a:Action s:mustUnderstand="1">
urn:SomeFaultAction
</a:Action>
</s:Header>
<s:Body>
<s:Fault>
<s:Code>
<s:Value>s:Receiver</s:Value>
<s:Subcode>
<s:Value xmlns:a="urn:MyNS">a:MyFaultCode</s:Value>
</s:Subcode>
</s:Code>
<s:Reason>
<s:Text xml:lang="en- US">The value must be > 10</s:Text>
</s:Reason>
<s:Detail>
<Program.SomeFaultDetail xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.datacontract.org/2004/07/MessageFaults">
<applicationName>SomeApp</applicationName>
<companyName>Contoso</companyName>
<dateOccurred>2006-06-14T12:34:44.52325- 04:00</dateOccurred>
</Program.SomeFaultDetail>
</s:Detail>
</s:Fault>
</s:Body>
</s:Envelope>
這段代碼展示的最顯著的特性就是 MessageFault如何做到消息版本獨立。第一次調用CreateAndShowMessage傳遞的 參數是MessageFault和 MessageVersion.Soap11WSAddressing10,結果是一個 SOAP 1.1 Fault。第2次調用CreateAndShowMessage傳遞的參數是同一個 MessageFault,但是MessageVersion變為 MessageVersion.Soap12WSAddressing10。結果就是一個SOAP 1.2 Fault。
前面代碼展示了如何從MessageFault創建一個Message。Message定義了 一個接受一個MessageFault參數工廠方法和幾個接受一個FaultCode的工廠方法 。Message的這些工廠方法允許程序創建一個MessageFault或FaultCode標志錯誤 。然後傳遞這個對象給WCF基礎結構裡的其它層去產生一個Message對象。
注釋:這看起來像個小功能,但是確帶來了巨大好處。作用上,MessageFault 類型的MessageVersion版本兼容能力允許在WCF基礎結構的另外部分來決定SOAP 消息版本。換句話說,WCF基礎結構裡只有一層為了傳輸需要知道SOAP消息版本 ,因此創建了一個熱拔插和可擴展的框架。
老徐備注
1.SOAP Fault 元素
來自 SOAP 消息的錯誤消息被攜帶於 Fault 元素內部。
如果已提供了 Fault 元素,則它必須是 Body 元素的子元素。在一條 SOAP 消息中,Fault 元素只能出現一次。
SOAP 的 Fault 元素用於下列 子元素:
子元素 描述 <faultcode> 供識別故障的代碼 <faultstring> 可供人閱讀的有關故障的說 明 <faultactor> 有關是誰引發故障的信息 <detail> 存留涉及 Body 元素的應用程序 專用錯誤信息
2.SOAP Fault Codes
在下面 定義的 faultcode 值必須用於描述故障時的 faultcode 元素中:
錯誤 描述 VersionMismatch SOAP Envelope 元素的無效命名 空間被發現 MustUnderstand Header 元素的一個直 接子元素(帶有設置為 "1" 的 mustUnderstand 屬性)無法被理解。 Client 消息被不正確地構成,或包含了不正確的 信息。 Server 服務器有問題,因此無法處理進行 下去。
參考: http://www.w3school.com.cn/soap/soap_fault.asp