WCF XML Stack

Microsoft .NET Framework 为了多种用途的XML 处理定义了一个丰富的类型集合。作为一个消息平台,WCF 比其他.NET 应用需要的正常功能还要多。例如,你在第2 章:“面向服务”里看到的一样,WCF 能够产生、发送、接受、处理二进制或者MTOM 编码的XML 消息。因为.NET Framework 没有提供这些功能,WCF API 自己定义类型来实现这些功能,我们可以使用这些类型与Message 类型直接交互。换句话说,WCF API 定义的类型可以转换Message 类型到一个特定编码格式。在System.Runtime.Serialization.dll 程序集的WCF System.Xml 命名空间下,有三个关键的类型定义它们负责序列化和编码Message 类型:XmlDictionary XmlDictionaryWriter XmlDictionaryReader 。为了讨论尽可能地简单,我讲使用XML 消息片段来阐述这些类型,而不是使用完全格式的SOAP 消息。在本章的后面部分,你会看到这些类型是如何来序列化和编码Message 类型的。

XmlDictionary类型【老徐备注1】

如它的名字的含义一样,一个XmlDictionary对象是许多对key-value的映射。很像字典或者词汇表,XmlDictionary可以用来替代简单的表达式而不会丢失任何含义。我们在日常生活里经常使用这种机制,但是我们却意识不到它的存在。考虑下面我说给朋友Rusty的话:“我昨晚看了一部关于潜水艇的电影。” Rusty将会听到这个消息并且做如下解释“我昨晚看了一部关于能在水面和水下航行的容器的电影。”第一句话比第二句话简单明了的多,它需要较少的表达时间。这个压缩和相关处理时间可以节省,因为我和Rusty共享一个词汇表。只要Rusty和我明白相同的词语,我们两个就可以高效地沟通。如果我对Rusty说:“这章经过苦思冥想(elucubration)终于完成了,”他估计不知道我在说什么。在这个例子里,我为了节约时间用了一个Rusty不知道的单词。因此,一个所有的参与者都知道的字典(或者是个词汇表)会提高效率。
冒着把这个比喻搞死的风险,另外有一点它也可以证明。当我对Rusty说,“我昨晚看了一部潜水艇的电影,”整个句子本身可以使用几种不同的方式和语言表达。如果你知道电影(movie)和潜水艇(submarine)的意思,你或许脑子里可以想想到这样的场景,黝黑的剧场里(或许可以闻到5块钱一通的爆米花香)另外还有荧幕上潜水艇的身影。话句话说,句子里的这些话激起了现实世界里的一些画面。就XML Infoset和编码而论,你可以映射XML Infoset到真实世界里的“事物”,你也可以把这些话转换为特定的编码。
在消息应用里,XmlDictionary也许被用来压缩序列化和编码过的消息大小,因此可以减小需要发送的消息占用的带宽。正如人们在高效地交流以前必须有一个公共的词汇表一样,发送者和接受者在消息交换的时候必须使用兼容的XmlDictionary对象。从内部来看,XmlDictionary定义了一个私有的可以表示SOAP消息里元素名字、属性和XML namespace声明的key-value对列表。
在直接使用XmlDictionary以前,我们有必要详细研究一下 XmlDictionary实例里存储的数据。XmlDictionary内部存储的key-value对是XmlDictionaryString类型的。一个 XmlDictionaryString类型定义的是一个Int32的Key属性和一个String类型的值。尽管XmlDictionaryString定义了共有的构造函数。XmlDictionaryString也不是由用户代码直接创建,而是通过增加XmlDictionaryString对象到XmlDictionary实例里。(我们会在本节的后面部分看到XmlDictionaryString的例子。)
XmlDictionary定义了一个无参的构造函数,还有一个很少使用的构造函数,这个构造函数可以接受表示最大 XmlDictionaryString元素个数的Int32数字。在构造实例结束以后,XmlDictionaryString可以通过调用实例的Add方法加入到XmlDictionary里。Add方法接受一个String类型,返回一个XmlDictionaryString实例,如下所示:
   
   
   
   
XmlDictionary dictionary = new XmlDictionary();List stringList = new List();// add element names to the dictionary and store in stringListstringList.Add(dictionary.Add("ReleaseDate"));stringList.Add(dictionary.Add("GoodSongs"));stringList.Add(dictionary.Add("Studio"));

因为XmlDictionary.Add方法返回一个 XmlDictionaryString的实例,局部变量dictionary包含3个XmlDictionaryString对象表示“ReleaseDate”、“GoodSongs”和“Studio”。此外,局部变量 stringList包含相同的3个XmlDictionaryString对象,存储在局部变量dictionary里。因为dictionary的三个对象不是公开访问的,所以必须另外存储一份,这样做实属无奈。我们可以通过迭代访问局部变量stringList看到每个XmlDictionaryString的Key 和Value属性。
   
   
   
   
Console.WriteLine( " entries in Collection: " );
foreach  (XmlDictionaryString entry  in  stringList) {
 Console.WriteLine(
" Key = {0}, Value = {1} " , entry.Key, entry.Value);
}
当前面的代码执行时,我们看到Key属性的值自动被赋于每个XmlDictionaryString:
整个集合如下:
   
   
   
   
Key  =   0 , Value  =  ReleaseDate
Key 
=   1 , Value  =  GoodSongs
Key 
=   2 , Value  =  Studio
注意到XmlDictionaryString的 Key属性是由XmlDictionary.Add方法赋值的。
XmlDictionary本身并没什么用处;在 WCF的XML的堆栈里它必须和其它的类型一起使用处理压缩工作。因此,现在我们看一下XmlDictionaryWriter类型,然后看看如何协调XmlDictionaryWriter和XmlDictionary一起进行压缩一个序列化和编码过的XML Infoset。
【老徐备注】
1. XmlDictionary:
实现用于优化 Windows Communication Foundation (WCF) 的 XML 读取器/编写器实现的字典。
字典在常见文本字符串和整数之间建立映射,并为压缩和解压缩 XML 提供一种有效的机制。Windows Communication Foundation (WCF) 使用静态和动态 2 种字典。
使用静态字典时,通信的两端都使用预定义的字典。
使用动态字典时,发送端可以添加其映射不在静态字典中的新字符串。动态字典与消息一起在带外发送。动态字典使用 XmlBinaryWriterSessionXmlBinaryReaderSession 类传输消息和映射。