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");
}
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
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());
// 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>
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的数量
这些复杂性约束可以抵御某种类型的拒绝服务 (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,如需转载请自行联系原作者