《WCF技术内幕》翻译25:第2部分_第5章_消息:创建一个消息(下)之MessageFault

Posted on 2009-12-06 22:14 Frank Xu Lei 阅读(139) 评论(0)   编辑 收藏 网摘 所属分类: 《WCF技术内幕》翻译, SOA and EAI

Messages and SOAP Faults

Message和SOAP Fault老徐备注1

SOAP Fault Anatomy

SOAP Fault 剖析

The MessageFault Type

MessageFault

老徐备注

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 &gt; 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 &gt; 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 元素的应用程序专用错误信息

 

2SOAP Fault Codes

在下面定义的 faultcode 值必须用于描述故障时的 faultcode 元素中:

错误

描述

VersionMismatch

SOAP Envelope 元素的无效命名空间被发现

MustUnderstand

Header 元素的一个直接子元素(带有设置为 "1" mustUnderstand 属性)无法被理解。

Client

消息被不正确地构成,或包含了不正确的信息。

Server

服务器有问题,因此无法处理进行下去。

参考:http://www.w3school.com.cn/soap/soap_fault.asp

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值