使用定制WCF MessageEncoder进行编码
【IT168 专稿】
一般情况下,MessageEncoder被使用在传输通道(Channel)上,虽然MessageEncoder可以被使用在通道栈的任何地方。但MessageEncoder经常被用作进行字节转换,以克服WCF消息类在传输数据时的缺陷。
一般来说,在通道中传输的字节是以多用途Mail扩展(MIME)格式形式存在的。对MIME的支持是一个WCF基石。WCF还可以建立基于SOAP协议进行交互的系统。事实上,WCF的功能足可以处理多种SOAP版本以及不同的XML数据格式。而MessageEncoder正在起来了在不同文件格式之间进行转换的功能。
建立自己的MessageEncoder的其他原因是我们可以想在整个通道栈里使用一个定制的Message类,或是当我们建立一个Message类时对这些输入数据进行转换。
无论我们写自己的MessageEncoder类的目的是什么,我们都可以使用同样的规则和工具集。现在,我们将要实现一个MessageEncoder,并给出相应的代码供读者进行参考。
本文除了给出建立自己的MessageEncoder类的例子外,并提供了一个虚拟的案例及解决方案。 一般来讲,MessageEncoder被嵌入到一个WCF中。按着规定,一个MessageEncoder类存在于一个传输通道类中。
1. 可以对类分别设计它们核对一致性、包括空格、以及指定一个特殊的编码格式。
MessageEncoder可以和.NET流一起工作。流是一些用于操作位于不同空间(如文件系统、内存或网络)字节的类。所有的流都有一个共同的基类来完成最常用的操作。
在前面的部分已经讲过,一般情况下,MessageEncoder一般用于传输通道中。而本文的例子岩石了如何在binding中合并一个MessageEncoder,并在一个传输通道中使用一个MessageEncoder。一般MessageEncoder对象实例由以下代码创建:
MessageEncoder是所有继承MessageEncoder的类的基类。因此,MessageEncoder包含了很多可以覆盖的方法,如ReadMessage和WriteMessage方法。它们的功能依赖于我们希望建立的信息类型。我们可以从本文的后面部分了解到如何实现一个新的ReadMessage和WriteMessage方法。
还有一些非常重要的可覆盖的属性和方法,用于处理"body"或Message类的数据部分,如ContentType、MediaType以及MessageVersion,它们都是关键的属性。其它的重要功能将依赖于类的具体实现。
buffer = mgr.TakeBuffer((int)streamFrom.Length); streamFrom.Read(buffer, 0, (int)streamFrom.Length); byteArray = new ArraySegment<byte>(buffer); msg = _encoder.ReadMessage(byteArray, mgr); ReadMessage的代码如下: public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType) { Message msg; XmlDocument doc = new XmlDocument(); doc.Load(stream); TestBodyWriter bw = new TestBodyWriter(doc); msg = Message.CreateMessage(this.MessageVersion,"",bw); return (msg); }
看了上面的代码,也许我们的第一个问题就是ArraySegment<byte>泛型类是什么?我们可以从.NET framework文档中可以看出,ArraySegment可以和Array类一起工作,并可以对数组的部分进行包装。
我们现在可以注意到,Message类的CreateMessage方法提供很多建立Message类的方法。对于这一点,我们可以回顾本文提供的所有重载的CreateMessage方法。接下来我们将看到如何将Message类转换回字节。
public override void WriteMessage(Message message, Stream stream) { XmlWriter writer = XmlWriter.Create(stream); XmlDictionaryWriter xmlDW = XmlDictionaryWriter.CreateDictionaryWriter(writer); message.WriteBodyContents(xmlDW); xmlDW.Close(); }
上面的代码是一个典型的实现。我使用了XmlDictionalWriter类将Message类的数据写到一个流中。当我们建立一个Message类实例时,Message对象被写到流中。同时OnWriteBodyContents事件被调用。在本文的开始部分,BodyWriter被XmlDocument类包装,因此,可以简单地使用XmlDocument和XmlWriter来处理Message类的内容。
MessageEncoder有以下几个特性。