消息传送协议

Windows Communication Foundation (WCF) 通道堆栈采用编码和传输通道将内部消息表示形式转换为其线路格式,并使用特定传输将其发送。 用于 Web 服务互作性的最常见传输是 HTTP,Web 服务使用的最常见编码是基于 XML 的 SOAP 1.1、SOAP 1.2 和消息传输优化机制(MTOM)。

本主题讨论 HttpTransportBindingElement 采用的下列协议的 WCF 实现细节。

规范/文档:

本主题介绍 TextMessageEncodingBindingElementMtomMessageEncodingBindingElement 所采用的以下协议的 WCF 实现详细信息。

规范/文档:

本主题介绍以下采用的协议 MtomMessageEncodingBindingElement 的 WCF 实现详细信息。

规范/文档:

本主题中使用以下 XML 命名空间和关联的前缀:

前缀 命名空间统一资源标识符(URI)
s11 http://schemas.xmlsoap.org/soap/envelope
s12 http://www.w3.org/2003/05/soap-envelope
wsa http://www.w3.org/2004/08/addressing
wsam http://www.w3.org/2007/05/addressing/metadata
wsap http://schemas.xmlsoap.org/ws/2004/09/policy/addressing
wsa10 http://www.w3.org/2005/08/addressing
wsaw10 http://www.w3.org/2006/05/addressing/wsdl
xop http://www.w3.org/2004/08/xop/include
xmime http://www.w3.org/2004/06/xmlmime

http://www.w3.org/2005/05/xmlmime
dp http://schemas.microsoft.com/net/2006/06/duplex

SOAP 1.1 和 SOAP 1.2

信封和处理模型

WCF 实现了遵循 Basic Profile 1.1 (BP11) 和 Basic Profile 1.0 (SSBP10) 的 SOAP 1.1 信封处理。 SOAP 1.2 信封处理在 SOAP12-Part1 之后实现。

本部分介绍 WCF 对 BP11 和 SOAP12-Part1 采取的某些实现选择。

强制标头处理

WCF 遵循 SOAP 1.1 和 SOAP 1.2 规范中关于处理标记为 mustUnderstand 的标头的规则,并针对这些规则进行了以下变更。

进入 WCF 通道堆栈的消息由与绑定元素关联的单个通道处理,例如文本消息编码、安全性、可靠消息传递和事务处理。 每个通道都识别来自关联命名空间的标头,并将其标记为已理解。 消息进入调度程序后,操作格式化程序读取相应消息/操作协定所期望的标头,并将其标记为已理解。 然后,调度程序验证是否还有任何标头未被理解,但仍标记为 mustUnderstand,如果是这样,则引发异常。 包含 mustUnderstand 收件人目标标头的邮件不会由收件人应用程序代码处理。

此类分层处理允许在 SOAP 节点的基础结构层和应用程序层之间分离:

  • B1111:未被理解的标头是在 WCF 基础结构通道堆栈处理消息之后,应用程序处理该消息之前检测的

    mustUnderstand标头值在 SOAP 1.1 和 SOAP 1.2 之间有所不同。 基本配置文件 1.1 要求 mustUnderstand SOAP 1.1 消息的值为 0 或 1。 SOAP 1.2 允许 0、1、falsetrue 作为值,但建议传输值的标准化表示形式,比如 xs:booleanfalsetrue)。

  • B1112:对于 SOAP 1.1 和 SOAP 1.2 版本的 SOAP 消息包,WCF 发出 mustUnderstand 值 0 和 1。 WCF 接受xs:boolean标头的整个mustUnderstand值空间(0,1,falsetrue

SOAP 故障

下面是特定于 WCF 的 SOAP 错误实现的列表。

  • B2121:WCF 返回以下 SOAP 1.1 错误代码: s11:mustUnderstands11:Client以及 s11:Server

  • B2122:WCF 返回以下 SOAP 1.2 错误代码: s12:MustUnderstands12:Sender以及 s12:Receiver

HTTP 绑定

SOAP 1.1 HTTP 绑定

WCF 遵循基本配置文件 1.1 规范第 3.4 节 3.4 实现 SOAP1.1 HTTP 绑定,并作出以下说明:

  • B2211:WCF 服务不实现 HTTP POST 请求的重定向。

  • B2212:WCF 客户端根据 3.4.8 支持 HTTP Cookie。

SOAP 1.2 HTTP 绑定

WCF 实现 SOAP 1.2 HTTP 绑定,如 SOAP 1.2 部分 2(SOAP12Part2)规范中所述,并作出以下说明。

SOAP 1.2 引入了application/soap+xml媒体类型的可选动作参数。 此参数可用于优化消息调度,而无需在不使用 WS-Addressing 时分析 SOAP 消息的正文。

  • R2221:application/soap+xml 操作参数出现在 SOAP 1.2 请求中时,必须与相应 WSDL 绑定内的 soapAction 元素的 wsoap12:operation 属性匹配。

  • R2222:当 application/soap+xml 动作参数存在于 SOAP 1.2 消息中时,必须在使用 WS-Addressing 2004/08 或 WS-Addressing 1.0 后匹配 wsa:Action

禁用 WS-Addressing 并且传入请求未包含动作参数时,消息 Action 被视为未指定。

WS-Addressing

WCF 实现 3 个版本的 WS 寻址:

  • WS-Addressing 2004/08

  • W3C Web 服务寻址 1.0 核心 (ADDR10-CORE) 和 SOAP 绑定 (ADDR10-SOAP)

  • WS-Addressing 1.0 - 元数据

终结点引用

WCF 实现的所有 WS-Addressing 版本都使用终结点引用来描述终结点。

终结点引用和 WS-Addressing 版本

WCF 实现许多基础结构协议,这些协议使用 WS-Addressing,特别是 EndpointReference 元素和 W3C.WsAddressing.EndpointReferenceType 类(例如 WS-ReliableMessaging、WS-SecureConversation 和 WS-Trust)。 WCF 支持将任一版本的 WS-Addressing 与其他基础结构协议一起使用。 WCF 终结点支持每个终结点一个 WS-Addressing 版本。

对于 R3111,与 WCF 终结点交换消息时使用的 EndpointReference 元素或类型的命名空间必须与此终结点实现的 WS-Addressing 版本匹配。

例如,如果某个 WCF 终结点实现了 WS-ReliableMessaging,由这样的终结点在 AcksTo 内部返回的 CreateSequenceResponse 标头使用 EncodingBinding 元素为此终结点指定的 WS-Addressing 版本。

终结点引用和元数据

很多情况下,需要对给定终结点进行元数据或元数据引用通信。

B3121:WCF 采用 WS-MetadataExchange (MEX) 规范第 6 节中描述的机制来按值或按引用包含终结点引用的元数据。

假设 WCF 服务需要使用令牌颁发者颁发的 http://sts.fabrikam123.com安全断言标记语言(SAML)令牌进行身份验证的情况。 WCF 终结点通过使用 sp:IssuedToken 断言(嵌套有指向令牌颁发机构的 sp:Issuer 断言)来描述这一身份验证要求。 访问该 sp:Issuer 断言的客户端应用程序需要知道如何与令牌颁发机构终结点进行通信。 客户端需要知道有关令牌颁发者的元数据。 使用在 MEX 中定义的终结点引用元数据扩展,WCF 提供对令牌颁发者元数据的引用。

<sp:IssuedToken>
  <sp:Issuer>
    <wsa10:Address>
      http://sts.fabrikam123.com
    </wsa10:Address>
    <wsa10:Metadata>
      <mex:Metadata>
        <mex:MetadataSection>
          <mex:MetadataReference>
            <wsa10:Address>
              http://sts.fabrikam123.com/mex
            </wsa10:Address>
          </mex:MetadataReference>
        </mex:MetadataSection>
      </mex:Metadata>
    </wsa10:Metadata>
  </sp:Issuer>
</sp:IssuedToken>

消息寻址标头

邮件头

对于这两个 WS-Addressing 版本,WCF 使用以下消息标头,按照规范:wsa:Towsa:ReplyTowsa:Actionwsa:MessageIDwsa:RelatesTo

B3211:对于所有 WS-Addressing 版本,WCF 采用但不生成现成的 WS-Addressing 消息头 wsa:FaultTowsa:From

与 WCF 应用程序交互的应用程序可以添加这些消息标头,WCF 将相应地处理它们。

引用参数和属性

WCF 根据各自的规范实现终结点引用参数和引用属性的处理。

B3221:配置为使用 WS-Addressing 2004/08 时,WCF 终结点不会区分处理引用属性和引用参数。

消息交换模式

Web 服务作调用中涉及的消息序列称为 消息交换模式。 WCF 支持单向、请求-答复和双工消息交换模式。 本部分阐明了消息处理 WS-Addressing 要求,具体取决于所使用的消息交换模式。

在整个部分中,请求方发送第一条消息,响应方接收第一条消息。

单向消息

当 WCF 终结点配置为支持给定 Action 消息遵循单向模式时,WCF 终结点遵循以下行为和要求。 除非另有指定,否则行为和规则适用于 WCF 中支持的两种 WS-Addressing 版本:

  • R3311:请求方必须包含 wsa:Towsa:Action 以及表示终结点引用所指定的所有引用参数的标头。 使用 WS-Addressing 2004/08 时,如果通过终结点引用指定了[引用属性],则必须将相应的标头添加到消息中。

  • B3312:请求者可以包含 MessageIDReplyTo标头和 FaultTo 标头。 接收方基础结构将忽略它们,它们将传递给应用程序。

  • R3313:使用 HTTP 且未在 HTTP 响应腿上发送消息时,响应方必须发送包含空正文和 HTTP 202 状态代码的 HTTP 响应。

    当 HTTP 传输正在使用且操作契约声称单向传递消息时,HTTP 响应仍然可以用于发送基础设施消息,例如,可靠性消息传输可以在 HTTP 响应中发送 SequenceAcknowledgement 消息。

  • B3314:WCF 响应方不发送错误消息以响应单向消息。

请求-答复

为给定 Action 消息配置 WCF 终结点以遵循请求-回复模式时,WCF 终结点遵循以下行为和要求。 除非另有指定,否则行为和规则适用于 WCF 中支持的 WS-Addressing 这两个版本:

  • R3321:请求者在请求中必须包括wsa:Towsa:Actionwsa:MessageID及所有终结点引用指定的引用参数或引用属性(或两者)的标头。

  • R3322:使用 WS-Addressing 2004/08 时, ReplyTo 还必须包含在请求中。

  • R3323:使用 WS-Addressing 1.0 且 ReplyTo 请求中不存在时,将使用与 [address] 属性相等 http://www.w3.org/2005/08/addressing/anonymous 的默认终结点引用。

  • R3324:请求者必须在回复消息中包含wsa:Towsa:Actionwsa:RelatesTo标头,以及请求中终结点引用所指定的所有引用参数或引用属性(或两者)的标头。

Web 服务寻址错误

R3411:WCF 生成由 WS-Addressing 2004/08 定义的以下错误。

代码 原因
wsa:DestinationUnreachable 到达的消息所带有的 ReplyTo 不同于为此通道建立的答复地址;在 To 标头中指定的地址上,没有终结点在进行侦听。
wsa:ActionNotSupported 与终结点关联的基础结构通道或调度程序无法识别标头中指定的 Action 操作。

R3412:WCF 生成由 WS-Addressing 1.0 定义的以下错误。

代码 原因
wsa10:InvalidAddressingHeader 重复wsa:Towsa:ReplyTowsa:Fromwsa:MessageID。 具有相同 wsa:RelatesToRelationshipType 重复。
wsa10:MessageAddressingHeaderRequired 缺少必需的 Addressing 标头。
wsa10:DestinationUnreachable 到达的消息所带有的 ReplyTo 不同于为此通道建立的答复地址。 在 To 标头中指定的地址上没有终结点在进行侦听。
wsa10:ActionNotSupported 与终结点关联的基础结构通道或调度程序不能识别在 Action 标头中指定的操作。
wsa10:EndpointUnavailable RM 通道发送回此错误,指示终结点将不会根据对 CreateSequence 消息的寻址标头的检查结果来处理序列。

上表中的代码映射到 SOAP 1.1 中的 FaultCode 和 SOAP 1.2 中带有 Code=Sender 的 SubCode

WSDL 1.1 绑定和 WS-Policy 断言

指示使用 WS-Addressing

WCF 使用策略断言来指示对特定 WS-Addressing 版本的终结点支持。

下面的策略断言具有终结点策略主题 [WS-PA],并指示从终结点收发的消息必须使用 WS-Addressing 2004/08。

<wsap:UsingAddressing />

此策略断言扩充了 WS-Addressing 2004/08 规范。

以下策略声明表明发送/接收的消息必须使用 WS-Addressing 1.0。

<wsam:Addressing/>

下面的策略断言具有终结点策略主题 [WS-PA],并指示从终结点收发的消息必须使用 WS-Addressing 2004/08。

<wsaw10:UsingAddressing />

wsaw10:UsingAddressing 元素借自于 [WS-Addressing-WSDL],并在符合该规范第 3.1.2 节的 WS-Policy 的上下文中使用。

使用寻址不会更改 WSDL 1.1、SOAP 1.1 和 SOAP 1.2 HTTP 绑定的语义。 例如,如果期望对发送到使用 Addressing 和 WSDL SOAP 1.x HTTP 绑定的终结点的请求进行回复,则答复必须通过 HTTP 响应发送。

对于通过 http 响应发送的答复,WS-AM 断言为:

<wsam:AnonymousResponses/>

完整的策略断言可能如下所示:

<wsam:Addressing>
    <wsp:Policy>
        <wsam:AnonymousResponses />
    </wsp:Policy>
</wsam:Addressing>

但是,有一些消息交换模式受益于在请求方和响应方之间建立两个独立的相反 HTTP 连接,例如,由响应方发送的无请求单向消息。

WCF 提供一项功能,通过该功能,两个基础传输通道可以形成复合双工通道,其中一个通道用于输入消息,另一个通道用于输出消息。 对于 HTTP 传输,复合双工提供了两个反向 HTTP 连接。 请求方使用一个连接将消息发送到响应方,响应方使用另一个连接将消息发送回请求者。

对于通过单独的 http 请求发送的答复,ws-am 断言是:

<wsam:NonAnonymousResponses/>

完整的策略断言可能如下所示:

<wsam:Addressing>
    <wsp:Policy>
        <wsam:NonAnonymousResponses />
    </wsp:Policy>
</wsam:Addressing>

在使用 WSDL 1.1 SOAP 1.x HTTP 绑定的终结点上,如果要使用以下具有终结点策略主题 [WS-PA] 的断言,要求将两个单独的反向 HTTP 连接分别用于从请求方到响应方以及从响应方到请求方传送消息。

<cdp:CompositeDuplex/>

上一语句导致对请求消息的 wsa:ReplyTo 标头有以下要求:

  • R3514:如果终结点使用 WSDL 1.1 SOAP 1.x HTTP 绑定,并且具有策略替代项,其中ReplyTo[address]断言与http://www.w3.org/2005/08/addressing/anonymous结合,则发送到终结点的请求消息必须具有wsap10:UsingAddressing标头,并且wsap:UsingAddressing属性不等于cdp:CompositeDuplex

  • R3515:请求消息发送到终结点时,如果该终结点使用 WSDL 1.1 SOAP 1.x HTTP 绑定,并具有附有ReplyTo断言而没有[address]断言的策略替代项,则必须具有http://www.w3.org/2005/08/addressing/anonymous标头,其中ReplyTo属性等于wsap10:UsingAddressing,或者根本没有cdp:CompositeDuplex标头。

  • R3516:如果终结点使用 WSDL 1.1 SOAP 1.x HTTP 绑定,并且具有一个包含ReplyTo断言且没有附加[address]断言的策略替代项,那么发送到终结点的请求消息必须包含一个http://www.w3.org/2005/08/addressing/anonymous标头,其中wsap:UsingAddressing属性等于cdp:CompositeDuplex

WS 寻址 WSDL 规范通过引入具有三个文本值(必需、可选和禁止)的元素 <wsaw:Anonymous/> 来指明针对 wsa:ReplyTo 标头(第 3.2 节)的要求,从而描述相似的协议绑定。 遗憾的是,在 WS-Policy 的上下文中,这样的元素定义不特别适合用作断言,因为它要求使用特定于域的扩展来支持将此类元素用作断言的备选项的交集。 这样的元素定义还指示 ReplyTo 标头的值在传输时与终结点行为相反,这使它只能特定于 HTTP 传输。

动作定义

WS-Addressing 2004/08 为 wsa:Action 元素定义了一个 wsdl:portType/wsdl:operation/[wsdl:input | wsdl:output | wsdl:fault] 属性。 WS-Addressing 1.0 WSDL 绑定 (WS-ADDR10-WSDL) 定义类似的属性 wsaw10:Action

两者之间唯一的区别在于默认 Action 模式语义(分别在 WS-ADDR 第 3.3.2 节和 WS-ADDR10-WSDL 第 4.4.4 节描述)。

两个终结点可共享相同的 portType(即 WCF 术语中的协定),但使用不同 WS-Addressing 版本。 但是,鉴于操作是由实现 portType 的端点定义的,并且在实现 portType 的端点中不应发生变化,因此无法支持两个默认的操作模式。

为了解决此争议,WCF 支持属性的 Action 单个版本。

B3521:WCF 使用 WS-ADDR10-WSDL 中定义的元素上的 wsaw10:Action 属性来确定对应消息的 wsdl:portType/wsdl:operation/[wsdl:input | wsdl:output | wsdl:fault] URI,而不考虑终结点使用的 WS-Addressing 版本。

在 WSDL 端口内使用终结点引用

WS-ADDR10-WSDL 第 4.1 节扩展 wsdl:port 元素以包含 <wsa10:EndpointReference…/> 子元素,以 WS-Addressing 术语描述终结点。 WCF 在 2004年8月的 WS-Addressing 扩展了这个实用程序,允许 <wsa:EndpointReference…/> 作为 wsdl:port 的子元素出现。

  • R3531:如果终结点具有附加策略替代项和 <wsaw10:UsingAddressing/> 策略断言,则相应的 wsdl:port 元素可以包含子元素 <wsa10:EndpointReference …/>

  • R3532:如果包含wsdl:port子元素,则<wsa10:EndpointReference …/>子元素wsa10:EndpointReference/wsa10:Address值必须与同级@addresswsdl:port/元素的属性的值wsdl:location匹配。

  • R3533:如果终结点具有附加的策略替代项和 <wsap:UsingAddressing/> 策略断言,则相应的 wsdl:port 元素可以包含子元素 <wsa:EndpointReference …/>

  • R3534:如果某个wsdl:port子元素包含子元素,则<wsa:EndpointReference …/>子元素wsa:EndpointReference/wsa:Address值必须与同级@addresswsdl:port/元素的属性的值wsdl:location匹配。

与 WS-Security 的结合

根据 WS-ADDR 和 WS-ADDR10 中的安全注意事项部分,建议将所有寻址消息标头与消息正文一起签名,以将它们绑定在一起。

当 WS-Security 用于消息完整性保护时,WS-Addressing 消息标头以及引用参数或属性(或两者)生成的标头必须与消息正文一起签名。

例子

单向消息

在这种情况下,发送者向接收者发送单向消息。 使用 SOAP 1.2、HTTP 1.1 和 W3C WS-Addressing 1.0。

请求消息结构:消息标头包括 wsa10:Towsa10:Action 元素。 消息正文包含应用程序命名空间中的特定 <app:Ping> 元素。

HTTP 标头:POST 中的目标与元素中的 wsa10:To URI 匹配。

Content-Type 标头具有 SOAP 1.2 所需的值 application/soap+xml 。 参数 charsetaction 包含。 action Content-Type 标头的参数与消息标头的值wsa10:Action匹配。

POST http://fabrikam123.com/Service HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8;  
              action="http://fabrikam123.com/Service/OneWay"
Host: 131.107.72.15
Content-Length: 1501
Expect: 100-continue
Proxy-Connection: Keep-Alive
<s12:Envelope>
  <s12:Header>
    <wsa10:To s12:mustUnderstand="1">
        http://fabrikam123.com/Service
    </wsa10:To>
    <wsa10:Action s12:mustUnderstand="1">
        http://fabrikam123.com/Service/OneWay
    </wsa10:Action>
  </s12:Header>
  <s12:Body>
    <Ping xmlns="http://fabrikam123.com/Service/">
      <Text>Hello World</Text>
    </Ping>
  </s12:Body>
</s12:Envelope>

接收方使用空的 HTTP 响应和状态 202 进行响应。 HTTP 响应的示例:

HTTP/1.1 202 Accepted
Date: Fri, 15 Jul 2005 08:56:07 GMT
Server: Microsoft-IIS/6.0
MicrosoftOfficeWebServer: 5.0_Pub
X-Powered-By: ASP.NET
X-AspNet-Version: 2.0.50215
Cache-Control: private
Content-Length: 0

SOAP 消息传输优化机制

本部分介绍 HTTP SOAP MTOM 的 WCF 实现详细信息。 MTOM 技术是与传统文本/XML 编码或 WCF 二进制编码相同的类的 SOAP 消息编码机制。 MTOM 包括以下内容:

  • [XOP] 描述的 XML 编码和打包机制,该机制将包含 base64 编码的二进制数据的 XML 信息项优化为单独的二进制部分。

  • XOP 包的 MIME 封装,该包将 XML Infoset 和 XOP 包的每个二进制部分序列化为单独的 MIME 部件。

  • 应用于 SOAP 1.x 信封的 MIME XOP 编码。

  • HTTP 传输绑定。

可以将 MTOM 与 WCF 的非 HTTP 传输配合使用。 但是,在本主题中,我们将重点介绍 HTTP。

MTOM 格式利用大量规范,涵盖 MTOM 本身、XOP 和 MIME。 此规范集的模块化使得重新构造格式和处理语义的确切要求有点困难。 本部分介绍 MTOM HTTP 绑定的格式和处理要求。

MTOM 消息编码

生成 MTOM 消息

[XOP] 节 3.1 介绍了使用包含 base64 值的元素信息项将 XML 编码到抽象定义的 XOP 包的过程。

以下步骤序列描述了特定于 MTOM 的编码过程:

  1. 确保要编码的 SOAP 信封不包含 [namespace name]http://www.w3.org/2004/08/xop/include 并且 [local name]Include 的元素信息项。

  2. 创建空 MIME 包。

  3. 在原始 XML 信息集中标识要优化的元素信息项。 要优化的项目中,构成[children]元素信息项的字符必须采用xs:base64Binary的规范形式(请参阅XSD-2,3.2.16 base64Binary),而且在非空白内容之前、内嵌或之后不得包含任何空白字符。

  4. 创建一个 XOP SOAP 信封,该信封是原始 SOAP 信封的副本,但在上一 xop:Include 步中标识的每个元素信息项的子项由构造如下的元素信息项替换:

    1. 通过将被替换字符处理为 base64 编码的数据,将其转换为二进制数据。

    2. 生成满足 R3133 和 R3134 要求的唯一 Content-ID 标头值。

    3. 使用值二进制生成 Content-Transfer-Encoding MIME 标头。

    4. 如果要优化的元素信息项(新插入的 xop:Include 元素信息项的 [parent])有一个 xmime:contentType 属性信息项,则生成一个带有 xmime:contentType 属性的值的 Content-Type MIME 标头。

    5. 生成一个新的二进制 MIME 部分,其内容由以下几项组成:从处理为 base64 的被替换数据解码的二进制数据、4b 中的 Content-ID、4c 中的 Content- Transfer-Encoding 标头,以及 Content-Type 标头(如果在步骤 4d 中生成)。

    6. 将一个 href 属性添加到 xop:Include 元素,其值为从 Content-ID 标头值(在步骤 4b 中生成)派生的 cid: uri。 删除封闭的“<”和“>”字符,对剩余字符串进行URL转义,并添加cid:前缀。 以下最小字符集需要根据 RFC1738 和 RFC2396 进行转义。 其他字符也可转义。

      Hexadecimal 00-1F , 7F, 20, "<" | ">" | "#" | "%" | <">
      "{" | "}" | "|" | "\" | "^" | "[" | "]" | "`" | "~" | "^"
      
  5. 使用步骤 4 中的 XOP SOAP 信封创建根 MIME 部件。

  6. 编写 HTTP 标头,包括 HTTP 内容类型标头。

  7. 编写 MIME 包。

处理 MTOM 消息

MTOM 消息的处理是前面“生成 MTOM 消息”部分中所述的过程的确切相反过程:

  1. 确保根 MIME 部件具有 Content-Type application/xop+xml

  2. 通过将包的根 MIME 部分分析为 XML 文档来构造 SOAP 信封。 字符编码由 charset 根 MIME 部分的 Content-Type 参数确定。

  3. 对于构造的 SOAP 信封中的每个元素信息项(有一个 xop:Include 元素信息项作为其 [children] 属性的唯一成员):

    1. 移除 cid: 前缀,取消转义 @href 元素的 xop:Include 属性的值中所有 URI 转义序列 (RFC 2396)。 将结果字符串括在“<”、“”>中。

    2. 找到 MIME 部件,其中包含与步骤 3a 中派生的字符串匹配的内容 ID 标头值。

    3. 将出现在每一项的 xop:Include 属性中的 children 元素信息项替换为字符信息项,这些字符信息项表示的是 MIME 部分(在步骤 3b 中标识)全部正文的规范 base64 编码(请参见 XSD-2,3.2.16 base64Binary)(实际是将 xop:Include 元素信息项替换为从包部分重新构造的数据)。

HTTP 内容类型标头

下面是 WCF 说明的列表,其中列出了从 MTOM 规范本身中声明的要求派生的 SOAP 1.x MTOM 编码消息的 HTTP 内容类型标头的格式,这些消息派生自 MTOM 和 RFC 2387。

  • R4131:HTTP 内容类型标头必须具有多部分/相关(不区分大小写)及其参数的值。 参数名称不区分大小写。 参数顺序不重要。

  • MIME 消息的内容类型标头的完整 Backus-Naur 形式(BNF)列在 RFC 2045 第 5.1 节中。

  • R4132:HTTP Content-Type 标头必须具有一个类型参数,其值 application/xop+xml 括在双引号中。

虽然使用双引号的要求在 RFC 2387 中并不明确,但文本观察到,所有多部分/相关媒体类型参数最有可能包含“@”或“/”等保留字符,因此需要双引号。

  • R4133:HTTP 内容类型标头应具有一个起始参数,该参数的值应该是包含 SOAP 1.x 信封的 MIME 部件的 Content-ID 标头的值,并用双引号括起来。 如果省略起始参数,则第一个 MIME 部分必须包含 SOAP 1.x 信封。

  • R4134:SOAP 1.1 MTOM 编码消息的 HTTP 内容类型标头必须包含带有文本/xml 值(括在双引号中)的 start-info 参数。

  • R4135:SOAP 1.2 MTOM 编码消息的 HTTP 内容类型标头必须包含 start-info 参数,其值为 "application/soap+xml",并用双引号括起来。

  • R4136:SOAP 1.x MTOM 编码消息的 HTTP 内容类型标头必须具有与 RFC 2046 第 5.1.1 节中定义的 MIME 边界 BNF 匹配的值(括在双引号中) 的边界参数

    boundary := 0*69<bchars> bcharsnospace
    bchars := bcharsnospace / " "
    bcharsnospace :=    DIGIT / ALPHA / "'" / "(" / ")" / "+"
                        / "_" / "," / "-" / "." / "/" / ":" / "=" / "?"
    

    例子:

    正确

    Content-Type: multipart/related; type="application/xop+xml";start=" <part0@tempuri.org>";boundary="uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=1";start-info="text/xml"
    

    正确

    Content-Type: Multipart/Related; type="application/xop+xml";start-info="text/xml";boundary="uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=1"
    

    不對

    Content-Type: Multipart/Related; type=application/xop+xml;start=" <part0@tempuri.org>";start-info="text/xml";boundary="uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=1"
    

Infoset MIME 部分

SOAP 1.x 信封封装为 XOP MIME 包的根部分,通常称为 infoset 部分。

  • R4141:SOAP 1.x 信封必须封装为 XOP MIME 包的根部分,称为 infoset 部分,并从 HTTP Content-Type 引用。

  • R4142:SOAP Infoset 部件必须包含以下 MIME 标头: Content-IDContent-Transfer-EncodingContent-Type

Content-ID 标头的格式由 RFC 2045 定义为

"Content-ID" ":" msg-id

其中 msg-id 在 RFC 2822(取代 RFC 822,在 RFC 2045 中引用)中定义,如下所示:

msg-id    =       [CFWS] "<" id-left "@" id-right ">" [CFWS]

并且实际上电子邮件地址括在“<”与“>”之间。 前缀 [CFWS] 和后缀已添加到 RFC 2822 中,用于携带注释,但不应用于保留互操作性。

R4143:Infoset MIME 部分的 Content-ID 标头的值必须遵循 RFC 2822 中的 msg-id 结果,并省略 [CFWS] 前缀和后缀部分。

过去,很多 MIME 实现对括在“<”和“>”中的值应为电子邮件地址的要求很宽松,除了电子邮件地址之外,还使用括在“absoluteURI”、“<>”中的。 本版本的 WCF 使用如下形式的 Content-ID MIME 标头值:

Content-ID: <http://tempuri.org/0>

R4144:MTOM 处理程序应接受符合以下宽松 msg-id 的 Content-ID 标头值。

msg-id-relaxed =     [CFWS] "<" (absoluteURI | mail-address) ">" [CFWS]
mail-address   =     id-left "@" id-right

MIME (RFC 2045)提供 Content-Transfer-Encoding 标头来传达 MIME 部件内容的编码。 为 Content-Transfer-Encoding 定义的默认值为 7 位,它不适用于大多数 SOAP 消息,因此需要 Content-Transfer-Encoding 标头才能提高互作性:

  • R4145:SOAP Infoset 部分必须包含 Content-Transfer-Encoding 标头。

  • R4146:如果 SOAP 信封字符编码为 UTF-8,则 Content-Transfer-Encoding 标头的值必须为 8 位。

  • R4147:如果 SOAP 信封字符编码为 UTF-16,则 Content-Transfer-Encoding 标头的值必须为二进制。

  • 根据 [XOP] 第 5 节,

  • R4148:SOAP1.1 Infoset 部分必须包含具有 application/xop+xml 媒体类型和 type="text/xml" 和 charset 参数的 Content-Type 标头

    Content-Type: application/xop+xml;
                  charset=utf-8;type="text/xml"
    
  • R4149:SOAP 1.2 Infoset 部件必须包含 Content-Type 标头,该标头具有媒体类型 application/xop+xml 和参数 type="application/soap+xml" 以及 charset

    Content-Type: application/xop+xml;
                  charset=utf-8;type="application/soap+xml"
    

    虽然 XOP 将charset参数application/xop+xml定义为可选,但为了实现类似于 BP 1.1 对charset媒体类型参数text/xml的要求的互操作性,该参数是必需的。

  • R41410:SOAP 1.x Infoset 部件的 Content-Type 标头上必须存在参数 typecharset

WCF 对 MTOM 的终结点支持

MTOM 的目的是对 SOAP 消息进行编码,以优化 base64 编码的数据。 下面是约束列表:

  • R4151:可以优化包含 base64 编码数据的任何元素信息项。

  • B4152:WCF 优化包含 base64 编码数据的元素信息项,长度超过 1024 字节。

配置为使用 MTOM 的 WCF 终结点将始终发送 MTOM 编码的消息。 即使没有满足所需条件的部件,消息仍经过 MTOM 编码(序列化为包含 SOAP 信封的单个 MIME 部件的 MIME 包)。

MTOM 的 WS-Policy 断言

WCF 使用以下策略断言来指示终结点的 MTOM 使用情况:

<wsoma:OptimizedMimeSerialization />
  • R4211:上述策略断言具有终结点策略主体,并指定必须使用 MTOM 优化发送到终结点和从终结点接收的所有消息。

  • B4212:在配置为使用 MTOM 优化时,WCF 终结点将一个 MTOM 策略断言添加到对应 wsdl:binding 的附加策略中。

与 WS-Security 的结合

MTOM 是一种编码机制,类似于 text/xml 和 WCF 二进制 XML。 MTOM 可以与 WS-Security 及其他 WS-* 协议自然结合:使用 WS-Security 进行保护的消息可使用 MTOM 优化。

例子

使用 MTOM 编码的 WCF SOAP 1.1 消息

POST http://131.107.72.15/Mtom/svc/service.svc/Soap11MtomUTF8 HTTP/1.1
SOAPAction: "http://xmlsoap.org/echoBinaryAsString"
Content-Type: multipart/related;type="application/xop+xml";
              start="<http://tempuri.org/0>";start-info="text/xml";
       boundary="uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=1"
Host: 131.107.72.15
Content-Length: 1501
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=1
Content-ID: <http://tempuri.org/0>
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="text/xml"
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
  <s:Body>
    <EchoBinaryAsString xmlns="http://xmlsoap.org/Ping">
      <array>
        <xop:Include
         href="cid:http%3A%2F%2Ftempuri.org%2F1%2F632618206521093670"
         xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
      </array>
    </EchoBinaryAsString>
  </s:Body>
</s:Envelope>
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=1
Content-ID: <http://tempuri.org/1/632618206521093670>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream
…Binary Content..
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=1

使用 MTOM 编码的 WCF 安全 SOAP 1.2 消息

在此示例中,使用 MTOM 和 SOAP 1.2 对消息进行编码,该消息使用 WS-Security 进行保护。 用于编码的二进制部分是对应于加密签名和加密正文的内容BinarySecurityTokenCipherValueEncryptedData。 请注意,由于CipherValueEncryptedKey的长度小于1024字节,WCF未将其纳入优化识别。

POST http://131.107.72.15/Mtom/service.svc/Soap12MtomSecureSignEncrypt HTTP/1.1
Content-Type: multipart/related; type="application/xop+xml";
              start="<http://tempuri.org/0>";
            boundary="uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=3";
              start-info="application/soap+xml";
              action="http://xmlsoap.org/echoBinaryAsString"
Host: 131.107.72.15
Content-Length: 1941
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=3
Content-ID: <http://tempuri.org/0>
Content-Transfer-Encoding: 8bit
Content-Type: application/xop+xml;charset=utf-8;type="application/soap+xml"
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
  <s:Header>
    <o:Security s:mustUnderstand="1" xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
      <u:Timestamp u:Id="uuid-4d4ee765-5717-4d53-9ac9-99bddc07df6c-5">
        <u:Created>2005-09-09T06:57:32.488Z</u:Created>
        <u:Expires>2005-09-09T07:02:32.488Z</u:Expires>
      </u:Timestamp>
      <o:BinarySecurityToken u:Id="uuid-4d4ee765-5717-4d53-9ac9-99bddc07df6c-2" ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3" EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">
        <xop:Include href="cid:http%3A%2F%2Ftempuri.org%2F1%2F632618206525089430" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
      </o:BinarySecurityToken>
      <e:EncryptedKey Id="_1" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
        <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p"/>
        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
          <o:SecurityTokenReference>
            <o:KeyIdentifier ValueType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509SubjectKeyIdentifier">Xeg55vRyK3ZhAEhEf+YT0z986L0=</o:KeyIdentifier>
          </o:SecurityTokenReference>
        </KeyInfo>
        <e:CipherData>          <e:CipherValue>oQfpxwT8/SAGyZQzKE2b4yO6dXuQj7pwJ+5CGL3Rf7C06bQ5ttMoQ9GLJcQYkXTzin+WwHEgs5bj5ml9HKTW9QAU5JJ6lksdymmQvWP5ZtGPBVchO4sofEGoCKmBiZL/DYS/cnbzgnc/3a6NYnc10y2fWGaGLiqa00zijAw7o0Y=</e:CipherValue>
        </e:CipherData>
      </e:EncryptedKey>
      <c:DerivedKeyToken u:Id="_2" xmlns:c="http://schemas.xmlsoap.org/ws/2005/02/sc">
        <o:SecurityTokenReference>
          <o:Reference URI="#_1"/>
        </o:SecurityTokenReference>
        <c:Nonce>OrEPRX7fISIS4sXYWPMv3g==</c:Nonce>
      </c:DerivedKeyToken>
      <e:ReferenceList xmlns:e="http://www.w3.org/2001/04/xmlenc#">
        <e:DataReference URI="#_3"/>
        <e:DataReference URI="#_4"/>
      </e:ReferenceList>
      <e:EncryptedData Id="_4" Type="http://www.w3.org/2001/04/xmlenc#Element" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
        <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
          <o:SecurityTokenReference>
            <o:Reference URI="#_2"/>
          </o:SecurityTokenReference>
        </KeyInfo>
        <e:CipherData>
          <e:CipherValue>
            <xop:Include href="cid:http%3A%2F%2Ftempuri.org%2F2%2F632618206525089430" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
          </e:CipherValue>
        </e:CipherData>
      </e:EncryptedData>
    </o:Security>
  </s:Header>
  <s:Body u:Id="_0">
    <e:EncryptedData Id="_3" Type="http://www.w3.org/2001/04/xmlenc#Content" xmlns:e="http://www.w3.org/2001/04/xmlenc#">
      <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
      <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
        <o:SecurityTokenReference xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
          <o:Reference URI="#_2"/>
        </o:SecurityTokenReference>
      </KeyInfo>
      <e:CipherData>
        <e:CipherValue>
          <xop:Include href="cid:http%3A%2F%2Ftempuri.org%2F3%2F632618206525089430" xmlns:xop="http://www.w3.org/2004/08/xop/include"/>
        </e:CipherValue>
      </e:CipherData>
    </e:EncryptedData>
  </s:Body>
</s:Envelope>
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=3
Content-ID: <http://tempuri.org/1/632618206525089430>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream
...Binary content of BinarySecurityToken - X509 Certificate...
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=3
Content-ID: <http://tempuri.org/2/632618206525089430>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream
...Binary serialization of the encrypted primary signature...
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=3
Content-ID: <http://tempuri.org/3/632618206525089430>
Content-Transfer-Encoding: binary
Content-Type: application/octet-stream
...Binary serialization of the encrypted Body...
--uuid:0ca0e16e-feb1-426c-97d8-c4508ada5e82+id=3--