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<XmlDictionaryString> stringList = new List<XmlDictionaryString>();// 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 种字典。
使用静态字典时,通信的两端都使用预定义的字典。
使用动态字典时,发送端可以添加其映射不在静态字典中的新字符串。动态字典与消息一起在带外发送。动态字典使用
XmlBinaryWriterSession 和
XmlBinaryReaderSession 类传输消息和映射。