本主题讨论如何创建自定义编码器。
在 Windows Communication Foundation(WCF)中,使用 绑定 指定如何在终结点之间跨网络传输数据。 绑定由 绑定元素序列组成。 绑定包括可选的协议绑定元素,例如安全性、所需的 消息编码器 绑定元素和所需的传输绑定元素。 消息编码器由消息编码绑定元素表示。 WCF 中包含三个消息编码器:二进制消息、消息传输优化机制(MTOM)和文本。
消息编码绑定元素将序列化传出 Message 并将其传递到传输层,或从传输层接收已序列化的消息并将其传递到协议层(如果存在),如果不存在协议层,则传递到应用程序。
消息编码器可将 Message 实例与网络表示形式互相转换。 虽然编码器被描述为位于通道堆栈中的传输层上方,但它们驻留在传输层内。 传输(例如 HTTP)根据传输标准的要求设置消息的格式。 编码器(例如 Text Xml)只需对消息进行编码。
连接到预先存在的客户端或服务器时,你可能没有选择使用特定消息编码。 但是,可以通过多个终结点(每个终结点使用不同的消息编码器)访问 WCF 服务。 当单个编码器不涵盖服务的整个受众时,请考虑通过多个终结点公开服务。 然后,客户端应用程序可以选择最适合它们的终结点。 使用多个终结点可将不同消息编码器的优势与其他绑定元素相结合。
系统提供的编码器
WCF 提供了多个系统提供的绑定,这些绑定旨在涵盖最常见的应用程序方案。 其中每个绑定都合并了传输、消息编码器和其他选项(例如安全性)。 本主题介绍如何扩展 WCF 中包含的 Text
、Binary
和 MTOM
消息编码器,或创建您自己的自定义编码器。 文本消息编码器支持纯 XML 编码和 SOAP 编码。 文本消息编码器的纯 XML 编码模式称为 POX(“普通旧 XML”)编码器,以将其与基于文本的 SOAP 编码区分开来。
有关系统提供的绑定绑定元素的组合的详细信息,请参阅 “选择传输”中的相应部分。
如何使用 System-Provided 编码器
使用派生自 MessageEncodingBindingElement的类将编码添加到绑定中。
WCF 提供派生自 MessageEncodingBindingElement 类的以下类型的绑定元素,这些元素可以提供文本、二进制和消息传输优化机制(MTOM)编码:
TextMessageEncodingBindingElement:XML 消息最可互作,但效率最低的编码器。 Web 服务或 Web 服务客户端通常可以理解文本 XML。 但是,将大型二进制数据块传输为文本并不有效。
BinaryMessageEncodingBindingElement:表示绑定元素,该元素指定用于基于二进制的 XML 消息的字符编码和消息版本控制。 这是编码选项中效率最高但兼容性最低的,因为它仅被 WCF 终结点支持。
MtomMessageEncodingBindingElement:表示绑定元素,该元素指定使用消息传输优化机制(MTOM)编码的消息使用的字符编码和消息版本控制。 MTOM 是一种高效技术,用于在 WCF 消息中传输二进制数据。 MTOM 编码器尝试在效率和互作性之间取得平衡。 MTOM 编码以文本形式传输大多数 XML,但通过传输 as-is来优化大型二进制数据块,无需将二进制数据转换为文本。
绑定元素创建二进制、MTOM 或文本 MessageEncoderFactory。 工厂创建二进制、MTOM 或文本 MessageEncoderFactory 实例。 通常,只有一个实例。 但是,如果使用会话,则可能会为每个会话提供不同的编码器。 二进制编码器使用它来协调动态字典(请参阅 XML 基础结构)。
这些ReadMessageWriteMessage方法是编码器的核心方法。 这些方法用于从流或 Byte 数组中读取消息。 当传输在缓冲模式下运行时,将使用字节数组。 消息总是写入流中。 如果传输必须缓冲消息,则它提供执行缓冲的流。
其他成员则使用支持内容、媒体类型和 MessageVersion。 传输调用这些编码器方法来测试传入消息是否可以由它解码,或者确定传出消息是否对此编码器有效。
这三个编码器实现中的每一个都会添加与特定编码相关的属性,并且完全可配置。 编码器还公开具有安全默认值的读取器配额。 有关配额的讨论,请参阅 XML 基础结构。
System-Provided 编码器的功能
系统提供的编码器提供了许多功能。
池
每个编码器实现都会尝试生成尽可能多的池。 减少分配是提高托管代码性能的关键方法。 若要完成此池化,实现代码将使用 SynchronizedPool
类。 C# 文件包含此类使用的其他优化的说明。
XmlDictionaryReader 和 XmlDictionaryWriter 实例已入池并重新初始化,以防止为每个消息分配新实例。 对于读取器,OnClose
回调将在调用 Close()
时回收读取器。 编码器还会回收构造消息时使用的一些消息状态对象。 这些池的大小可以通过派生自 MaxReadPoolSize
的这三个类之一的 MaxWritePoolSize
和 MessageEncodingBindingElement 属性配置。
二进制编码
当二进制编码使用会话时,必须将动态字典字符串传递给消息的接收方。 为此,请使用动态字典字符串为消息添加前缀。 接收方去除字符串,将其添加到会话中,并处理消息。 正确传递字典字符串需要使用缓冲的传输机制。
字符串通过内部 AddSessionInformationToMessage
方法追加到消息中。 它将字符串以 UTF-8 格式添加到消息的前面,并在每个字符串前添加它们的长度作为前缀。 随后,整个字典标头都将以数据长度作为前缀。 反向操作由内部ExtractSessionInformationFromMessage
方法来执行。
除了处理动态字典关键字之外,缓冲的会话消息将采用独有的方式接收。 二进制编码器使用内部 MessagePatterns
类来解构二进制流,而不是通过文档创建读取器并对其进行处理。 其想法是,大多数消息都有一组特定的标头,这些标头在 WCF 生成时按特定顺序显示。 模式识别系统根据其预期分解消息。 如果成功,它将初始化对象 MessageHeaders 而不分析 XML。 否则,它会退回到标准方法。
MTOM 编码
该 MtomMessageEncodingBindingElement 类具有一个名为 MaxBufferSize 的额外配置属性。 这会在读取消息的过程中设置允许缓冲的数据量上限。 XML 信息集(Infoset)或其他 MIME 部件可能需要缓冲以将所有 MIME 部件重新组合到单个消息中。
为了可以正确使用 HTTP,内部 MTOM 消息编码器类为 GetContentType
(内部)和 WriteMessage
提供了一些内部 API,这些 API 是公用的,可以重写。 必须进行更多的通信,以确保 HTTP 标头中的值与 MIME 标头中的值一致。
在内部,MTOM 消息编码器使用 WCF 的文本读取器,类似于文本编码器。 主要的区别在于它优化了大型二进制数据块或“二进制大型对象”(BLOBs),在嵌入消息字节之前不将它们转换为 Base-64 编码。 而是将这些 BLOB 保持提取状态,并以 MIME 附件的形式进行引用。
编写自己的编码器
若要实现自己的自定义消息编码器,必须提供以下抽象基类的自定义实现:
从消息的内存中表示形式转换为可写入流的表示形式封装在类中 MessageEncoder ,该表示形式充当支持特定 XML 编码类型的 XML 读取器和 XML 编写器的工厂。
您必须重写的此类的主要方法包括:
WriteMessage 它采用对象 MessageEncodingBindingElement 并将其写入对象 Stream 。
ReadMessage 接收一个 Stream 对象和最大标头大小,并返回一个 Message 对象。
它是在这些方法中编写的代码,用于处理标准传输协议与自定义编码之间的转换。
接下来,需要编写用于创建自定义编码器的工厂类的代码。 重写 Encoder 以返回自定义 MessageEncoder 的实例。
然后通过重写 MessageEncoderFactory 方法将自定义的 CreateMessageEncoderFactory 连接至用于配置服务或客户端的绑定元素堆栈,以便返回此工厂的实例。
WCF 提供了两个示例,演示此过程的示例代码: 自定义消息编码器:自定义文本编码器 和 自定义消息编码器:压缩编码器。