Message和SOAP Fault老徐备注1
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对象。
老徐备注
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