首页 / 软件开发 / WCF / 《WCF技术内幕》26
《WCF技术内幕》262011-06-20 博客园 Frank Xu Lei译《WCF技术内幕》26:第2部分_第5章_消息:Buffered vs Streamed、序列化和反序列化消息Buffered vs. Streamed消息当我们在终结点之间流动的消息时,我们会本能地想到缓存。换个方式来说 ,我们假设程序接收到一个Message时,它已经知道整个Message。这种方式称作 缓存模式(buffering)。与之相对的就是流处理模式(streaming),并且有2种 流处理模式(streaming)。第一种是推模型(push model),发送者按照自己 的节奏推送字节流到接收者。当流数据发送的时候,发送者把数据写到本地缓存 直到写满为止,数据会发生给接收者,接收者会从本地缓冲区读取数据。第二种 机制成为拉模型(pull model)。当流数据发送的时候,接收者从发送者请求数 据,在收到请求以后,发送者发送请求的数据。这个过程会重复执行知道请求的 数据发送完毕。WCF 基础结构实现了第二种流处理方法。在WCF里,Message的消息头块通常是缓存起来的,消息内容可以buffered或 者 streamed模式。缓存区的大小默认是64KB.(你会在第8章里了解如何改变这 个设置。)如果消息体是streamed模式,它的大小就是无限制的。实际上,这意 味着我们可以在WCF里传递流媒体。不是所有的消息都是流处理消息体元素。例 如,小的消息就不需要streamed模式;缓存模式会更加高效地处理它们。更确切 地说,一个大的消息本质上验证是十分困难的。想一下,一个例子,假如使用 streamed模式发送一个30分钟长的电影作为消息体的消息。电影非常不错,并且 可以在接收完毕前就可以播放给观众。如果数据流终止,并且没任何发送结束标 记,处理错误就变得不太可能了,因为用户可能已经看到数据了,同样地,如果 一个程序已经对数据做了数据签名,这个签名只能在整个数据流结构和缓存以后 才能验证了,这就不适合使用streamed模式处理消息体数据。序列化消息既然你已经学习了如何创建消息,现在我们来研究一下如何序列化消息的全 部或者某一部分。首先,Message类型上的所有序列化方法名称都是以Write开始 ,而且这些方法都接受XmlWriter或者XmlDictionaryWriter类型的参数。消息的 实际序列化工作由XmlWriter或者XmlDictionaryWriter对象完成,而不是直接由 Message对象完成。记得前面关于XmlDictionaryWriter的讨论,实际的序列化包 括消息序列化和编码2个步骤。序列化小的方法原型如下:public void WriteStartEnvelope(XmlDictionaryWriter writer);
public void WriteStartBody(XmlDictionaryWriter writer);
public void WriteStartBody(XmlWriter writer);
public void WriteBody(XmlDictionaryWriter writer);
public void WriteBody(XmlWriter writer);
public void WriteBodyContents(XmlDictionaryWriter writer);
public void WriteMessage(XmlDictionaryWriter writer);
public void WriteMessage(XmlWriter writer);
WriteMessage方法序列化消息的全部内容到XmlWriter或者 XmlDictionaryWriter包装的Stream里。因为这些方法序列化整个消息,因此与 其它方法相比,它们的使用频率最高。Message类型同样定义了对于消息序列化进行粒度控制的方法。例如, WriteBody方法序列化body标签和元素到XmlWriter或者XmlDictionaryWriter包 装的Stream里。WriteBodyContents方法,话句话说,序列化body元素(没有 body标签)到XmlDictionaryWriter包装的Stream里。WriteStartEvelope方法简 单的写<s:Envelope标签到到XmlDictionaryWriter包装的Stream里。在 WriteStartEnvelope之后立即调用WriteStartBody方法,会写XML namespace到 envelope,并且序列化body开始标签,从序列化内容完全忽略消息头。实际上, 如果我们需要在使用这些方法的时候对消息序列化做额外的控制,我们肯定想序 列化消息头的内容。这个功能隐含在Message对象模型里,并且会在本章后面的 “Message Headers类型”一节里做相应的介绍。记住,如果你想手工序列化一 个消息,你必须明确序列化消息头块。还没有明确的方法可以写envelope或 body的结束标签。但是,为了写envelope或body的结束标签,我们直接调用 XmlWriter. WriteEndElement方法。反序列化消息在接受程序里普遍存在的一个任务就是消息的反序列化。消息的反序列化是 从一个序列化的消息创建一个新的消息的别称。因为我们已经过了如何创建一个 Message对象,同样也讲了大部分的消息反序列化的内容。更确切地说,我们已 经学习了如何使用XmlDictionaryReader类型从一个Stream或者Byte创建一个 Message。想一下我们关于Message工厂方法的讨论,其中一种创建消息体的方法就是传 递Object给工厂方法。同样的方式,我们或许需要从一个Message实例反序列化 Object。为了这个目的,Message类型定义了从Message对象反序列化消息体的成 员。这些方法的原型如下;public T GetBody<T>();
public T GetBody<T>(XmlObjectSerializer serializer);
泛型方法GetBody允许调用者反序列化消息体的内容到T类型的对象里。另外 一个方法接受一个XmlObjectSerializer参数,因此为消息体的反序列化提供了 扩展点。不论我们调用哪个方法,我们必须知道Message 的消息体内包含的类型 信息。如果我们泛型方法里使用的类型和消息体的类型不兼容,就会抛出一个 SerializationException异常。