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对象:
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里看到的一样:
// 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
【 老徐的博客】
【作 者】: Frank Xu Lei
【地 址】: http://www.cnblogs.com/frank_xl/
【中文论坛】:微软WCF中文技术论坛
【英文论坛】:微软WCF英文技术论坛