《WCF技术内幕》翻译23:第2部分_第5章_消息:XmlDictionaryReader和回到Message

XmlDictionaryReader类型

(本节主要讲解的是XmlDictionaryReader类型,如何实例化一个对象,如何使用其来反序列化XmlDictionaryWriter处理的数据。最后是:回到Message)
XmlDictionaryReader抽象类型继承自System.Xml.XmlReader,因此继承了很多XmlReader的特性。和XmlReader一样,XmlDictionaryReader定义了几个工厂方法,他们返回的是XmlDictionaryReader的子类型的实例。更确切地说,XmlDictionaryReader包装了一个Stream,并定义了许多以Read开头的方法。因此,由于继承的层次关系,使用XmlDictionaryReader和XmlReader很相似。
和XmlReader不同,XmlDictionaryReader的目的是为了读取序列化的和编码过的XML Infosets ,并且可以由选择地借助XmlDictionary来实现语义压缩的反向处理。作用上,XmlDictionaryReader和XmlDictionaryWriter正好相反,并且2个类型的对象模型非常相似。让我们从XmlDictionaryReader的创建方法开始学习,然后详细研究如何使用它的Read方法。因为XmlDictionaryReader和XmlDictionaryWriter的相似性,本节会比上一节XmlDictionaryWriter要简短一些。

创建一个XmlDictionaryReader对象

XmlDictionaryReader类型定义了几个工厂方法,所有这些方法都直接或者间接地,接受一个Stream 或Byte[]的引用。通常来说,面向stream的方法与面向buffer的方法很相似。绝大部分,这些工厂方法都是重载一下4个方法: CreateDictionaryReader, CreateTextReader, CreateMtomReader和CreateBinaryReader,它们的行为与XmlDictionaryWriter的相同名字工厂方法对应。为了避免重复,我们将会关注XmlDictionaryReader的工厂方法的显著特性上。
几个工厂方法接受一个Stream的引用,这些面向stream的工厂方法使用的其它参数包含一个XmlDictionaryQuotas对象的引用和一个OnXmlDictionaryReaderClose委托。在所有的情况下,前者调用后者,为XmlDictionaryQuotas和OnXmlDictionaryReaderClose参数传递null引用。
XmlDictionaryQuotas类型是一个状态容器,它用来定义与XML反序列化相关的重要的阀值。例如,这个类型定义反序列化中用到的节点深度的最大值、反序列化最大的String长度、消息体的最大数组长度等等【老徐备注1】
OnXmlDictionaryReaderClose委托在XmlDictionaryReader 的Close方法几乎结束的时候调用。当这个委托被激活以后,XmlDictionaryReader的大部分状态被设置为null。因此,这个委托可以用来作为提醒机制(很像一个事件event),但不会提供XmlDictionaryReader状态相关的任何有价值的信息(除非Null是有价值的)。Message编码器使用OnXmlDictionaryReaderClose委托去把 XmlDictionaryReader对象放到对象池。这些编码器依赖OnXmlDictionaryReaderClose委托这样的提醒,它会返回一个资源池里的XmlDictionaryReader实例。
一下代码演示了如何实例化一个XmlDictionaryReader对象:
private static void CreateTextReader() { 
Console.WriteLine("==== Creating XML Dictionary Text Reader ===="); 
MemoryStream stream = new MemoryStream(); 
    
// create an XmlDictionaryWriter and serialize/encode some XML 
XmlDictionaryWriter writer = XmlDictionaryWriter.CreateTextWriter(stream, 
        Encoding.BigEndianUnicode, false); 
writer.WriteStartDocument(); 
        writer.WriteElementString("SongName", 
                                                            "urn:ContosoRockabilia", 
                                                            "Aqualung"); 
writer.Flush(); 
stream.Position = 0; 
    
// create an XmlDictionaryReader to decode/deserialize the XML 
XmlDictionaryReader reader = XmlDictionaryReader.CreateTextReader( 
        stream, Encoding.BigEndianUnicode, new XmlDictionaryReaderQuotas(), 
        delegate { Console.WriteLine("closing reader"); } ); 
reader.MoveToContent(); 
Console.WriteLine("Read XML Content:{0}",reader.ReadOuterXml()); 
    
Console.WriteLine("about to call reader.Close()"); 
reader.Close(); 
Console.WriteLine("reader closed"); 
}

当以上代码执行的时候,就会产生以下输出:

==== Creating XML Dictionary Text Reader ====
Read XML Content:
<SongName xmlns="urn:ContosoRockabilia">Aqualung</SongName>
about to call reader.Close()
closing reader
reader closed
着重指出一下,XmlDictionaryReader的其它工厂方法接受的参数和XmlDictionaryWriter的工厂方法几乎一一对应。这些参数与在XmlDictionaryWriter类型里的作用一样。

借助XmlDictionary生成XML数据

既然已经看了如何实例化XmlDictionaryWriter和XmlDictionaryReader,现在我们就学习一下如何使用XmlDictionary读取二进制编码的XML。如下面的代码所示,这与你在XmlDictionaryWriter里看到的一样:
MemoryStream stream = new MemoryStream(); 
// create the dictionary and add dictionary strings 
XmlDictionary dictionary = new XmlDictionary(); 
List<XmlDictionaryString> stringList = new List<XmlDictionaryString>(); 
stringList.Add(dictionary.Add("SongName")); 
stringList.Add(dictionary.Add("urn:ContosoRockabilia")); 
    
// use an XmlDictionaryWriter to serialize some XML使用XmlDictionaryWriter序列化一些XMl 
using (XmlDictionaryWriter writer = 
        XmlDictionaryWriter.CreateBinaryWriter(stream, dictionary, null)) { 
    
// write using the dictionary - element name, namespace, value 
writer.WriteElementString(stringList[0], stringList[1], "Aqualung"); 
writer.Flush(); 
Console.WriteLine("Using Dictionary, wrote {0} bytes", 
                                        stream.Position); 
stream.Position = 0; 
Byte[] bytes = stream.ToArray(); 
Console.WriteLine(BitConverter.ToString(bytes)); 
    
// create an XmlDictionaryReader passing the Stream创建XmlDictionaryReader并传递Stream 
// and an XmlDictionary 
XmlDictionaryReader reader = 
        XmlDictionaryReader.CreateBinaryReader(stream, dictionary, new 
            XmlDictionaryReaderQuotas()); 
reader.Read(); 
Console.WriteLine("data read from stream:\n{0}\n", 
        reader.ReadOuterXml()); 
当代码执行的时,输出一下结果:
XmlDictionaryWriter (Binary w/dictionary) wrote 14 bytes 
42-00-0A-02-99-08-41-71-75-61-6C-75-6E-67 
data read from stream: 
<SongName xmlns="urn:ContosoRockabilia">Aqualung</SongName>
注意到传递到CreateBinaryWriter方法上的XmlDictionary和传递到XmlDictionaryReader方法上的XmlDictionary是一个对象的引用。诚然,传递同一个对象的引用的是有些粗糙但是能保证XmlDictionaryWriter 和XmlDictionaryReader使用一个词汇表,但是它说明了XmlDictionaryReader可以解释XmlDictionaryWriter使用XmlDictionary压缩的数据。

回到Message类型

既然我们已经研究过了序列化和编码一个Message的相关类型,现在该重新关注一下Message类型了。Message对象模型初略估计包含45个public或protected的成员。这些成员中包含返回Message实例的工厂方法、序列化Message的方法、反序列化Message的方法、返回Message信息的属性、处理Message头部的属性和清理Message的方法。
【老徐备注】
1.    为交换的 Soap 消息指定复杂性约束的 XmlDictionaryReaderQuotas。下面的备注部分中提供了这些约束的默认值。
这些复杂性约束可以抵御某种类型的拒绝服务 (DOS) 攻击,这些攻击试图利用消息复杂性来占用终结点处理资源。表达这些约束及其默认值的属性如下所示:
字典读取器最重要的安全功能是配额。必须为字典读取器工厂方法指定配额实例。默认构造函数创建安全默认值(与编码默认值相同),并且类具有静态 Max 属性,用于创建不带配额的读取器。
5.maxDepth="32" 
最大节点深度
6.maxStringContentLength="8192" 
最大内容长度
7.maxArrayLength="16384"
最大数组长度
8.maxBytesPerRead="4096" 
最大每次读取长度
9.maxNameTableCharCount="16384"
最大NameTableChar的数量
我曾经在MSDN WCF中文论坛解释过,WCF使用到的所有的Max的作用。
http://social.microsoft.com/Forums/zh-CN/wcfzhchs/thread/73f31b97-bef5-47c6-b50e-d0d3140d8efb



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


上一篇:【重磅】中国新一代人工智能规划专家解读,外媒:中国要统治AI


下一篇:什么是分布式消息中间件?