《WCF技术内幕》翻译9:第1部分_第2章_面向服务:消息编码

简介:

消息编码

  随着时间的流逝,也许我们会条件反射式地认为 XML SOAP )是一个结构文本。毕竟,文本是人可读的,每个计算机系统也可以处理文本。基于文本的 XML 的普遍共性与我们的与其它系统交互的想法产生了共鸣。可以容易的解释的基于文本的 XML 本质上会体积变大。可以理解使用 XML 会带来性能损失。就像要花费点精力把信装到信封里一样,它需要一些处理时间与 XML 交互。某些情况下,基于文本的 XML 数据大小限制了它的应用,特别是当我们要通过网络发送一个 XML 消息的时候。
  此外,如果我们限制自己使用基于文本的 XML ,那么我们怎么才能在 XML 文档里发送二进制数据(像音乐或者视频)?如果你已经阅读了标准的 XMLSchema 数据类型,你会发现 2 个二进制数据类型: xs:base64Binary  xs:hexBinary 本质上说,两个数据类型都代表一组有序的 8 位字节。使用这些 XML 数据类型或许可以解决一些嵌入二进制数据到文档中的问题,但是事实上,这已经使得性能问题更加糟糕。众所周知的问题就是, base64 编码会增加数据 30% 的大小。这个情况对于 xs:hexBinary 更坏,因为它会增加位原来的 2 倍大小。两个数据都是基于 UTF-8 编码的假设。如果我们采用 UTF-16 编码,这些倍数因子都会翻倍增加。
XML  信息集( XML Infoset
  为了找到性能的瓶颈的答案,我们详细来看一下 XML 文档的结构。如果我们看一下规范, XML 是一个精确的撰写结构化数据的语法 ( 定义在  http://www.w3.org/TR/REC-xml/)。它要求定义格式良好的XML 文档必须包涵一个开始和结束元素、一个根节点等等。奇怪的是, XML 规范发布以后,激起了抽象定义 XML 文档的需求。 XML 信息集(定义在 http://www.w3.org/TR/xml-infoset/ )提供了这个抽象定义。
  实际上, XML 信息集定义是项目之间的关系,不定义任何具体的语法,我们能够解释许多不同的消息编码,包括一些比文本更高校的编码格式,而不需要修改我们的程序。
SOAP XML 信息集
  记得 SOAP 是建立在 XML 之上的。这个产生一个问题:到底 SOAP 消息是建立在早期的 XML 语法上还是 XML 信息集上呢?答案是 2 者都有。 2 SOAP 规范并存: SOAP 1.1  SOAP 1.2 SOAP1.1 建立在旧的 XML 语法上, SOAP1.2 建立在 XML  信息集上。有这么一个事实,就可以猜想 SOAP1.2 建立的消息 SOAP1.1 的解析器可能无法阅读。 WCF 是建立在 SOAP1.2 XML 信息集上),但是它可以同时处理 SOAP 1.1  SOAP 1.2 的消息。
   WCF 可以用来和定制与其它实际的消息编码一起工作,只要消息是遵照 SOAP1.1 或者 SOAP1.2 的(它可以和不是 SOAP 消息一起工作)。如你将会在接下来的章节里看到的一样, WCF 是一个可灵活接入和组合的架构。所以自定义编码器可以轻易地安装到 WCF 的管道上。当一个新的编码器开发完毕,微软或者第三方都可以在消息堆栈里创建和插入它。我将会在第 6 章:《通道》里详细介绍消息编码器 。现在我们来看一下 WCF 里的编码器。在写本书的时候, WCF 提供了三个编码器:文本( text )、(二进制) binary   消息传输优化机制( Message Transmission Optimization Mechanism  MTOM)
文本编码器
  和你从它的名字里猜到的一样,文本编辑器的输出结果是基于文本编码的消息。每个明白 Unicode 文本的系统都可以阅读和处理这个编码器传递来的消息,在与别的非 WCF 系统互操作时,这个是一个很帮的选择。二进制数据通过 xs:base64Binary 扩展样式定义( XSD 数据类型 可以包涵到基于文本的消息里。这是一个使用 WCF 文本编码器编码过的消息(为了清晰,移除了一部分元素)。
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"> 

        <s:Header></s:Header> 

        <s:Body> 

            <SubmitOrder xmlns="http://wintellect.com/OrderProcess"> 

                <Order xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 

                <OrderByte xmlns="http://wintellect.com/Order"> 

mktjxwyxKr/9oW/jO48IhUwrZvNOdyuuquZEAIcy08aa+HXkT3dNmvE/ 

+zI96Q91a9Zb17HtrCIgtBwmbSk4ys2pSEMaIzXV3cwCD3z4ccDWzpWx1/ 

wUrEtSxJtaJi3HBzBlk6DMW0eghvnl652lKEJcUJ6Uh/LRlZz3x1+aereeOgdLkt4gCnNOEFECL8CtrJtY/taPM4A+k/ 

4E1JPnBgtCRrGWWpVkO0UqRXahz2XbShrDQnzgDwaHDf/ 

fHDXfZgpFwOgPF1IG88KQZO0JncSYKIp5I8OPYTeqD0yVhB8QSt9sWw59yzLHvU65UKoYfXA7RvOqZkJGtV6wZAgGcA= 



                    </OrderByte> 

                <OrderNumber xmlns="http://wintellect.com/Order"> 

                        12345 

                    </OrderNumber> 

                </Order> 

            </SubmitOrder> 

        </s:Body> 

</s:Envelope>
二进制编码器
  二进制编码器是最高效的消息编码器,并且只适用与 WCF- -WCF 的通信。在 WCF 所有的编码器中,二进制编码器产生最小的消息。记住这个编码器产生一个序列化的信息集,即使它是二进制编码格式。将来可能,一个标准的二进制编码会被采用,这些编码的类型可以显著第改善消息应用的性能。
MTOM 编码器
  MTOM 编码器根据 MTOM 规范创建消息。( MTOM 规范可以在这里查到 http://www.w3.org/TR/soap12-mtom/ )因为 MTOM 编码已经规范化,所以其它厂商可以自由创建发送和接受消息的基础结构。结果, MTOM 消息编码的 WCF 消息就可以发送给非 WCF 的应用(只要它们理解 MTOM )。通常来说, MTOM 为了允许高效第传输包涵二进制数据的消息,它也提供了数字签名。 MTOM 消息编码可以通过多用途网络邮件扩展协议( MIME )启用这些特性。 MTOM 消息的内容被 XML- 二进制优化包装方法所定义。更多信息: http://www.w3.org/TR/xop10/ .
  在运行时, MTOM 编码器为了数字签名创建一个基于 base64 编码的代表,让原始二进制数据可以在消息里打包。一个 MTOM 消息看起来如下:
// start of a boundary in the multipart message多部分消息的分界线 

--uuid:+id=1 

Content-ID: <http://wintellect.com/0> 

Content-Transfer-Encoding: 8bit 

// set the content type to xop+xml,设置内容类型xop+xml 

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

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"> 

<s:Header></s:Header> 

<s:Body> 

        <SubmitOrder xmlns="http://wintellect.com/OrderProcess"> 

            <order xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 

                <OrderByte xmlns="http://wintellect.com/Order"> 

                     // add a reference to another message part 

                    <xop:Include href=cid:http://wintellect.com/1/12345 

                     xmlns:xop="http://www.w3.org/2004/08/xop/include"/> 

                </OrderByte> 

                <OrderNumber xmlns="http://wintellect.com/Order"> 

                    12345 

             </OrderNumber> 

            </order> 

        </SubmitOrder> 

</s:Body> 

</s:Envelope> 

// end of the boundary in the first message part第一部分的内容结束边界 

--uuid:+id=1 

// add the binary data as an octect stream增加二进制数据为八位字节流 

Content-ID: <http://wintellect.com/1/12345> 

Content-Transfer-Encoding: binary 

Content-Type: application/octet-stream 

// raw binary data here这里是原始二进制数据 

注意到二进制数据被原样保坤在 SOAP 消息里的另一块区域里。因为二进制数据被打包到 SOAP 消息的外部区域,那么这么才能给 SOAP 进行数字签名呢?如果我们使用基于 XML 的安全机制,像 XML 加密和 XML 数字签名里描述的一样,我们不能引用外部的二进制流。这些加密个签名机制要求被保护的数据包装在 SOAP 消息里。咋一看,对于多部分的消息还真没有什么办法。事实上,这是直接网络消息封装( DIME )和 SOAP 附件的致命弱点。 MTOM 提供了一个有趣的解决办法。
   MTOM 编码规范规定一个 MTOM 消息能够包涵二进制数据在 base64 编码的字符里,后者二进制流在额外的消息部分里。它也表示一个基于 base64 编码的二进制数据的代表在处理的时候必须可用。换句话说,额外的消息部分可以为消息传输创建,但是内联的 base64 数据必须对一些操作如:应用数字签名临时可用。当消息处于内联的基于 base64 编码的状态,基于 XML 编码的安全机制可以被应用到 SOAP 消息里。安全机制应用结束,消息可以被序列化为多部分消息。当接受者接受消息的时候,这个消息可以被 XML 安全规范机制强制根据一些列规则进行验证。
  非常有意思地看到,当大量二进制消息是基于 base64 编码或者二进制流编码在额外的消息部分的时候, WCF MTOM 编码器能够正确地选择序列化。 WCF 编码器使用二进制数据大小作为选择的依据。在之前的消息里, OrderBytes 元素大约 800k 。如果我们减少 OrderBytes 的大小到 128k ,在检查一下消息格式,我们可以看到:
// start of a boundary in the multipart message,多部分消息开始边界 

--uuid:+id=1 

Content-ID: <http://wintellect.com/0> 

Content-Transfer-Encoding: 8bit 

// set the content type to xop+xml 

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

<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"> 

<s:Header></s:Header> 

<s:Body> 

        <SubmitOrder xmlns="http://wintellect.com/OrderProcess"> 

            <order xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> 

                <OrderByte xmlns="http://wintellect.com/Order"> 

kF+k2CQd/lCitSYvXnLhuOtaMCk/tZaFZIWeW7keC3YvgstAWoht/wiOiR5+HZPo+TzYoH+qE9vJHnSefqKXg6mw/ 

9ymoV1i7TEhsCt3BkfytmF9Rmv3hW7wdjsUzoBl9gZ1zR62QVjedbJNiWKvUhgtq8hAGjw+uXlttSohTh6xu7kkAjgoO 

3QJntG4qfwMQCQj5iO4JdzJNhSkSYwtvCaTnM2oi0/fBHBUN3trhRB9YXQG/mj7+ZbdWsskg/ 

Lo2+GrJAwuY7XUROKyY+5hXrAEJ+cXJr6+mKM3yzCDu4B9bFuZv2ADTv6/MbmFSJWnfPwbH1wK0LQi7Ixo95iF 

                </OrderByte> 

                <OrderNumber xmlns="http://wintellect.com/Order"> 

                    12345 

                </OrderNumber> 

            </order> 

        </SubmitOrder> 

</s:Body> 

</s:Envelope> 

--uuid:+id=1-
  这个例子里, WCF 编码器序列化二进制元素为基于 base64 编码的 string 。这个优化是相当符合 MTOM 规范。
选择恰当的编码
  选择消息编码器强迫你去考虑当前和未来的消息使用问题。大部分来说,应用互操作性和消息里的数据类型会决定我们的选择。性能,在决定那个编码器是最适合我们系统的时候,也会考虑进来。表 2-1 基于消息类型和那种系统可以可以发送和接受消息列举了编码情况。
 2-1: 消息编码器排列和场景
消息类型
Binary
Text
MTOM
Text 内容 只与 WCF  交互
1
2
3
Text 内容 与现代非 WCF 系统交互
N/A
1
2
Text 内容 与旧的非 WCF systems  交互
N/A
1
N/A
大二进制内容 只与 WCF  交互
1
3
2
大二进制内容 与现代非 WCF 系统交互
N/A
2
1
大二进制内容 , ,  与旧的非 WCF systems  交互
N/A
1
N/A
小二进制内容 只与 WCF  交互
1
2
3
小二进制内容 与现代非 WCF 系统交互
N/A
1
2
小二进制内容 , ,  与旧的非 WCF systems  交互
N/A
1
N/A
不应该惊讶,二进制编码器是 WCF 与其它 WCF 系统交互最高效的编码器。我们也许吃惊的是这个事实,在端到端的情况下, MTOM 消息编码是比文本编码器效率还低。互操作性和二进制数据大小是你选择 MTOM 和文本编码器的因素。绝大多数情况, MTOM 编码消息只能发送给 MTOM 编码器的系统。写本书的时候, MTOM 是一个很新的规范,所以只有现代系统可以高效地处理 MTOM 消息。从性能的角度来看, MTOM 编码器只有当包装到消息里的二进制数据很大的时候才有意义。 MTOM 不应该用在不包括二进制数据的消息里,因为 MTOM 的性能此时比文本编码器效率更低。因此,独立测试一个在产品环境里使用的消息非常重要。
   幸运的是,我们可以在第 4 章: WCF 101 里看到, WCF 就是这些编码选择都不需要大的改变应用程序的方式来设计的。事实上,这使得一个服务可以与多种不同的消息编码交互成为可能。举例来说,一个服务可以与两个二进制编码和文本编码的消息交互。这个场景的好处在于当与别的 WCF 参与者通信的时候,服务可以快速执行,并且可以与别的平台通信,比如 JAVA



 本文转自 frankxulei 51CTO博客,原文链接:http://blog.51cto.com/frankxulei/318626,如需转载请自行联系原作者

相关文章
|
网络架构
消息(6)——WCF,构建简单的WCF服务,MTOM编码
构建一个简单的WCF服务。 以Web服务类似的步骤由IIS进行宿主服务。建立的步骤: 1 新建3.5网站 2 添加WCF服务,自动生成契约接口与实现,这里改动一下,添加个字串参数: [ServiceContract] public interface IFirstService {     [OperationContract]     void DoWork(string strContent); }   服务中的方法什么都不用做。
698 0
|
C#
C#面向服务编程技术WCF从入门到实战演练
一、WCF课程介绍 1.1、Web Service会被WCF取代吗? 对于这个问题阿笨的回答是:两者在功能特性上却是有新旧之分,但是对于特定的系统,适合自己的就是最好的。不能哪一个技术框架和行业标准作比较,任何对于二者的比较都是错误的,因为两者根不不在同一个范畴里。
1353 0
|
10月前
|
前端开发
WCF更新服务引用报错的原因之一
WCF更新服务引用报错的原因之一
|
9月前
|
C# 数据安全/隐私保护
c#如何创建WCF服务到发布(SqlServer版已经验证)
c#如何创建WCF服务到发布(SqlServer版已经验证)
38 0