WCF消息之XmlDictionaryWriter

原文:WCF消息之XmlDictionaryWriter

XmlDictionaryWriter,是一个抽象类,从该类中派生了WCF,以便执行序列化和反序列化。

 

它有4种格式书写器:

CreateBinaryWriter,用于创建写入WCF二进制xml格式的实例

CreateMtomWriter,用于创建以MTOM格式mxl的实例

CreateTextWriter,用于创建写入文本xml的实例

 

(一)CreateTextWriter



以文本格式写入xml,工厂方法有3个重载:

CreateTextWriter(Stream)

CreateTextWriter(Stream, Encoding)

CreateTextWriter(Stream, Encoding, Boolean)

 

其中第三个方法中的bool参数用于指定流操作:如果为 true,则完成时编写器关闭流;否则为 false。而字符编码Encoding默认的是utf-8。且只支持utf-8,或unicode大头或小头三种编码。

unicode大头小头就是:Big-Endian,Little-Endian(直译过来就是大头结尾,小头结尾)。其中big-endian是在低地址放高位字节,另一个则相反。例如:0x12345678这个16进制的数字

big-endian

低地址——高地址

12|34|56|78

 

Little-endian

低地址——高地址

78|56|34|12

(说实在的,big-endian更符合人们的习惯)

例如:“赵”字的unicode的big-endian(可以在记事本中写个赵字,然后保存时编码选择big-的,然后在ultra中打开,看它的16进制编码),只看它的BOM部分就知道了:FE FF

在程序中这个编码可以由Encoding的属性来设置:Encoding.BigEndianUnicode

 

public void TestTextWriter()

{

    MemoryStream ms = new MemoryStream();

using (XmlDictionaryWriter writer =

XmlDictionaryWriter.CreateTextWriter(ms,

Encoding.BigEndianUnicode, false))

    {

writer.WriteStartDocument();

writer.WriteElementString("UserName", "Songjiang");

writer.Flush();

    }

 

    byte[] bb = ms.ToArray();

    Console.WriteLine(BitConverter.ToString(bb));

 

    ms.Position=0;

    Console.WriteLine(new StreamReader(ms).ReadToEnd());

 

    ms.Close();

}

这里的工厂方法的第三个参数指定为了false,设置在完成wirter的关闭后,不自动关闭对应流,因为后边还要用到这个流。用完后再显示关闭可以了。

它的输出为:

FE-FF-00-3C-00-3F-00-78-00-6D-00-6C-00-20-00-76-00-65-00-72-00-73-00-69-00-6F-00-6E-00-3D-00-22-00-31-00-2E-00-30-00-22-00-20-00-65-00-6E-00-63-00-6F-00-64-00-69-00-6E-00-67-00-3D-00-22-00-75-00-74-00-66-00-2D-00-31-00-36-00-42-00-45-00-22-00-3F-00-3E-00-3C-00-55-00-73-00-65-00-72-00-4E-00-61-00-6D-00-65-00-3E-00-53-00-6F-00-6E-00-67-00-6A-00-69-00-61-00-6E-00-67-00-3C-00-2F-00-55-00-73-00-65-00-72-00-4E-00-61-00-6D-00-65-00-3E

 

<?xml version="1.0" encoding="utf-16BE"?><UserName>Songjiang</UserName>

 

字符编码可以在流字节和xml看出来:FEFF的BOM,和encoding=”utf-16be”

 

再看看utf-8编码下的情况(只在CreateTextWriter方法中将编码改为utf-8即可):

3C-3F-78-6D-6C-20-76-65-72-73-69-6F-6E-3D-22-31-2E-30-22-20-65-6E-63-6F-64-69-6E-67-3D-22-75-74-66-2D-38-22-3F-3E-3C-55-73-65-72-4E-61-6D-65-3E-53-6F-6E-67-6A-69-61-6E-67-3C-2F-55-73-65-72-4E-61-6D-65-3E

<?xml version="1.0" encoding="utf-8"?><UserName>Songjiang</UserName>

 

Utf-8的BOM是EF BB BF,但这里的字节却没有。可见,对于Text wirter来说,utf-8编码下,utf-8的BOM是省略的,在组包过程中,这点要注意。

 

(二)CreateBinaryWriter



以MTOM格式写入xml,工厂方法有2个重载:

CreateMtomWriter(Stream, Encoding, Int32, String)

CreateMtomWriter(Stream, Encoding, Int32, String, String, String, Boolean, Boolean) 

 

这里说一下第一个方法:

前2个参数不用说,一个管流,一个管字符编码。然后是int参数,用于设置缓冲的最大字节数,第4个字串型用于设置soap头中的ContentType属性。(ContentType用于描述内容类型的字符串,格式通常为:类型/字类型,其中类型为常规内容范畴,而子类为特定内容类型。对于这个,可以网上找下,例如:text/html)

public void TestMTOMWriter()

{

    MemoryStream ms = new MemoryStream();

XmlDictionaryWriter _writer =

XmlDictionaryWriter.CreateMtomWriter(ms,

Encoding.UTF8, 1000, "Application/soap+xml");

    _writer.WriteStartDocument();

    _writer.WriteElementString("UserName", "Songjiang");

 

    _writer.Flush();

 

    byte[] bb = ms.ToArray();

 

    Console.WriteLine(BitConverter.ToString(bb));

    StreamReader sr = new StreamReader(ms);

    ms.Position = 0;

    string sx = sr.ReadToEnd();

    Console.WriteLine(sx);

    ms.Close();

    sr.Close();

}

结果:

4D-49-4D-45-2D-56-65-72-73-69-6F-6E-3A-20-31-2E-30-0D-0A-43……省略

 

MIME-Version: 1.0

Content-Type: multipart/related;type="application/xop+xml";

boundary="551a8456-58c9-46ff-b481-f81747b71098+id=1";

start="<http://tempuri.org/0/634052866078593750>";

start-info="Application/soap+xml"

 

--551a8456-58c9-46ff-b481-f81747b71098+id=1

Content-ID: <http://tempuri.org/0/634052866078593750>

Content-Transfer-Encoding: 8bit

Content-Type: application/xop+xml;charset=utf-8;type="Application/soap+xml"

 

<?xml version="1.0" encoding="utf-8"?><UserName>Songjiang</UserName>

--551a8456-58c9-46ff-b481-f81747b71098+id=1--

 

看第二个方法:

CreateMtomWriter(Stream, Encoding, Int32, String, String, String, Boolean, Boolean)

前4个参数已经说过,

Stream stream,

Encoding encoding,

int maxSizeInBytes,

string startInfo,

string boundary,



string startUri,



bool writeMessageHeaders,



bool ownsStream

 

现在说后4个,从字面上可以看出,第5个用于设置MIME边界字串,第6个用于设置MIME部分的ID uri,第7个用于设置是否写入消息头,最后一个用于设置在完成writer的关闭时,是否关联关闭对应流。也写一个例子:

XmlDictionaryWriter _writer = XmlDictionaryWriter.

CreateMtomWriter(ms, Encoding.UTF8, 1000, "Application/soap+xml"

,"thisisBoundary============","startUri===1234567890",true,false);

 

MIME-Version: 1.0



Content-Type: multipart/related;type="application/xop+xml";



boundary="thisisBoundary============";



start="<startUri===1234567890>";



start-info="Application/soap+xml"

 

--thisisBoundary============

Content-ID: <startUri===1234567890>

Content-Transfer-Encoding: 8bit

Content-Type: application/xop+xml;charset=utf-8;type="Application/soap+xml"

 

<?xml version="1.0" encoding="utf-8"?><UserName>Songjiang</UserName>

--thisisBoundary============--

其中,黑体部分标出了边界和起始标识串的位置,而斜体字部分就是消息头,这部分由这个方法的第7个布尔参数来控制。(对于边界,它以一行开始,且前2个字符为--,而总边界结束也由—结尾,还要注意起始头添加了一对尖括号,这些内容可以查阅相关文档)

对于soap中的MIME附件,这个方法可以很好的实现。

(三)CreateMtomWriter



以二进制写入xml

它有4个重载方法:

CreateBinaryWriter(Stream)

CreateBinaryWriter(Stream, IXmlDictionary)

CreateBinaryWriter(Stream, IXmlDictionary, XmlBinaryWriterSession)

CreateBinaryWriter(Stream, IXmlDictionary, XmlBinaryWriterSession, Boolean)

 

它的参数为:

Stream stream,

IXmlDictionary dictionary,

XmlBinaryWriterSession session,

bool ownsStream

 

其中,第一个与第四个就不说了,第二个表示用于压缩的XmlDictionary对象,如果不压缩则写null,第三个用于允许发送者和接收者自动创建和协调一个动态的XmlDictionary

 

public void TestBinaryWriter()

{

    MemoryStream ms = new MemoryStream();

XmlDictionaryWriter _writer =

XmlDictionaryWriter.CreateBinaryWriter(ms, null,null);

 

    _writer.WriteStartDocument();

    _writer.WriteElementString("UserName", "Songjiang");

    _writer.Flush();

 

    byte[] bb = ms.ToArray();

 

    Console.WriteLine(BitConverter.ToString(bb));

 

    StreamReader sr = new StreamReader(ms);

    ms.Position = 0;

    string sx = sr.ReadToEnd();

    Console.WriteLine(sx);

    _writer.Close();

    ms.Close();   

    sr.Close();

}

结果:

40-08-55-73-65-72-4E-61-6D-65-99-09-53-6F-6E-67-6A-69-61-6E-67

@€serName�  Songjiang

 

更多详细内容请见:

http://www.cnblogs.com/frank_xl/archive/2009/12/01/1614830.html

时间: 2024-09-23 00:34:13

WCF消息之XmlDictionaryWriter的相关文章

wcf-C# WCF 消息队列报错,求救

问题描述 C# WCF 消息队列报错,求救 win10系统,添加完消息队列组件之后,写了个控制台的WCF MSMQ小例子. 运行服务端总是报错,试过网上能查到的配置文件还有代码的方式修改了,还是报那个错误. "System.InvalidOperationException"类型的未经处理的异常在 System.ServiceModel.dll 中发生 其他信息: 打开队列时出错.确保已安装和运行 MSMQ,队列存在并且具有正确的读取权限.内部异常可能包含更多信息. 请问有么没人给点思

《WCF技术内幕》22:第2部分_第5章_消息:XmlDictionaryWriter

(概述:这一部分介绍了XmlDictionaryWriter类型的相关概念:如何创建, 使用一个对象,然后讲述了如何进行Text.二进制和MTOM编码.最后介绍了 XmlDictionary的作用[老徐备注2],已经各种编码的效率问题.你会了解为 WCF支持的几种编码格式的基本原理.) XmlDictionaryWriter XmlDictionaryWriter类型为Message类型的序列化和编码的.它继承自 System.Xml.XmlWriter,因此继承了很多XmlWriter 的属性

WCF 消息帧格式

在TCP/IP协议栈中,当数据通过协议栈向下流动时,每一层都要给数据增加控制信息用于确保正确的传递.控制信息放置在被传送数据的开始,称之为包头,这种在协议栈中每一层都增加传递信息的过程称为封装.也就是说,栈中每层软件对传递的数据都要进行格式化,使之与特定的协议相适应,即每层都在上层的基础上加一个与协议相对应的包头:而当数据在协议栈中反方向(由底层向上)流动时,协议软件就以相反的方式处理数据,即每一层都剥去栈中对应层增加的包头,然后将数据传递给上一层,这就是拆封. 数据是网络和TCP/IP协议栈传

wcf消息拦截,AfterReceiveRequest中拦截,但调试或者获取元数据的时候不需要验证

问题描述 publicobjectAfterReceiveRequest(refSystem.ServiceModel.Channels.Messagerequest,System.ServiceModel.IClientChannelchannel,System.ServiceModel.InstanceContextinstanceContext){//主要是这里拦截消息,但直接打开service.svc不想验证如何判断//或者客户端通过地址获取元数据的时候也不验证//请问,如何在这里判断当

wcf 消息队列异常

问题描述 staticvoidMain(string[]args){stringqueueName=@".Private$SampleQueue";//stringqueueName2=@".Private$FromCenterQueue";MessageQueuemq=null;if(!MessageQueue.Exists(queueName))mq=MessageQueue.Create(queueName);//else//mq=newMessageQueu

WCF技术剖析之十八:消息契约(Message Contract)和基于消息契约的序列化

在本篇文章中,我们将讨论WCF四大契约(服务契约.数据契约.消息契约和错误契约)之一的消息契约(Message Contract).服务契约关注于对服务操作的描述,数据契约关注于对于数据结构和格式的描述,而消息契约关注的是类型成员与消息元素的匹配关系. 我们知道只有可序列化的对象才能通过服务调用在客户端和服务端之间进行传递.到目前为止,我们知道的可序列化类型有两种:一种是应用了System.SerializableAttribute特性或者实现了System.Runtime.Serializat

WCF分布式开发步步为赢(13):WCF服务离线操作与消息队列MSMQ

之前曾经写过一个关于MSMQ消息队列的文章:WCF分布式开发必备知识 (1):MSMQ消息队列 ,当时的目的也是用它来作为学习WCF 消息队列MSMQ编程的 基础文章.在那篇文章里,我们详细介绍了MSMQ消息队列的基本概念.安装.部 署.开发.调试等相关问题.今天我们来学习WCF分布式开发步步为赢(13):WCF 服务离线操作与消息队列MSMQ.在WCF框架下使用MSMQ消息队列服务编程. 这 里我会给出一个使用WCF MSMQ实现离线请求的DEMO示例程序. 全文结构是:[1]MSMQ基本概念

《WCF技术内幕》翻译10:第1部分_第2章_面向服务:填写消息地址

填写消息地址 现在我们已经看过了与消息交互的实体,详细剖析了消息结构,然后看了一 下WCF 提供了几个消息编码器,现在我们来看一下如何在详细发送的时候表示我 们要发送的目的地.毕竟,除非能发送给接受者,否则消息等于是毫无用处.和 邮政服务需要一个良好格式的地址结构一样,面向服务的消息同样也需要一个定 义良好的地址结构.这节里,我们将会建立自己的地址结构(Scheme),看它可 以不可以广泛适用于所有的消息应用系统,然后把它关联到那个和WCF消息一起 使用的地址结构上. 在传输里标记地址VS在消息

WCF技术内幕

<WCF技术内幕>39:第2部分_第7章_通道管理器:通道工厂和本章 <WCF技术内幕>38:第2部分_第7章_通道管理器:通道侦听器 <WCF技术内幕>37:第2部分_第7章_通道管理器:概述和通道管理 <WCF技术内幕>36:第2部分_第6章_通道:创建自定义通道和本章 <WCF技术内幕>35:第2部分_第6章_通道:通道功能 <WCF技术内幕>34:第2部分_第6章_通道:通道接口和基本类型 <WCF技术内幕>33: