现在的位置: 首页 > 综合 > 正文

《WCF技术内幕》翻译26:第2部分_第5章_消息:Buffered vs Streamed、序列化和反序列化消息

2018年01月22日 ⁄ 综合 ⁄ 共 4372字 ⁄ 字号 评论关闭

http://blog.csdn.net/book_frank_xl/article/details/4968263

Posted on 2009-12-08 20:03 Frank Xu Lei 阅读(299) 评论(1)  编辑 收藏 网摘 所属分类: 《WCF技术内幕》翻译SOA
and EAI
 

Buffered
vs. Streamed消息

序列化消息

反序列化消息

检查Message 是否是SOAP Fault

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异常。

检查Message 是否是SOAP Fault

正如你看到的,Message类型的实例表示一个SOAP 消息或者SOAP Fault。当接受程序反序列化一个Message的时候,它必须能够确定这个Message是否是一个SOAP Fault,因为通常SOAP 消息和SOAP Fault的执行路径不同。因此,Message定义了一个只读属性IsFault。简而言之,一旦一个Message对象从进来的Stream or Byte反序列化完毕,IsFault属性会标记Message是否是一个SOAP Fault,这也是WCF基础结构对于反序列化的消息作出的第一次检查。我们可以通过改变前面代码里CreateAndShowMessage方法来演示这个属性的功能,如下所示;

private static void CreateAndShowMessage(MessageFault messageFault,
                                         MessageVersion version) {
 Message message = Message.CreateMessage(version,
                                          messageFault,
                                          "urn:SomeFaultAction");
 // commented out for clarity
 // Console.WriteLine("{0}/n", message.ToString());
 
 // ** New code begins here **
 MemoryStream stream = new MemoryStream();
 // write the Message to a Stream
 XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(
      stream,null, null, false);
 message.WriteMessage(writer);
 writer.Flush();
 
 stream.Position = 0;
 
 // read the Message from the Stream从Stream读取消息
 XmlDictionaryReader reader =
      XmlDictionaryReader.CreateBinaryReader(stream, new
        XmlDictionaryReaderQuotas());
 message = Message.CreateMessage(reader, Int32.MaxValue, version);
 
 // check if it is a Fault检查消息是否是SOAP Fault
 Console.WriteLine("the message {0} a SOAP Fault",
      message.IsFault ? "is" : "is not");
}

当这些代码执行的时候(像前面的代码),产生下面的输出:

the message is a SOAP Fault
the message is a SOAP Fault

注意到对于连个创建对象Message.IsFault属性都返回true,这里着重指出的是对于所有的表示SOAP Fault的Message对象,Message.IsFault属性都返回true,不管消息数据的编码和版本是什么。

 


 

老徐的博客
【作      者】:Frank Xu Lei
【地      址】:http://www.cnblogs.com/frank_xl/
【中文论坛】:微软WCF中文技术论坛
【英文论坛】:微软WCF英文技术论坛

抱歉!评论已关闭.