加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

通过WCF扩展实现消息压缩

发布时间:2020-12-16 09:10:48 所属栏目:asp.Net 来源:网络整理
导读:对于需要进行大规模数据传输的WCF应用来说,对于请求消息和回复消息进行传输前的压缩,不但可以降低网络流量,也可以提高网络传输的性能。由于WCF的扩展性,我们可以采用不同的方式实现对消息的压缩,本文提供一种比较简单的实现方式。[源代码从这里下载] 一

对于需要进行大规模数据传输的WCF应用来说,对于请求消息和回复消息进行传输前的压缩,不但可以降低网络流量,也可以提高网络传输的性能。由于WCF的扩展性,我们可以采用不同的方式实现对消息的压缩,本文提供一种比较简单的实现方式。[源代码从这里下载]

一、三种可行的消息压缩方案
二、DataCompressor——用于数据压缩与解压缩组件
三、MessageCompressor——用于消息压缩与解压的组件
四、CompressionMessageFormatter——用于对请求/回复消息压缩和解压缩的组件
五、CompressionOperationBehaviorAttribute——将CompressionMessageFormatter用于WCF运行时框架的操作行为
六、查看结构压缩后的消息
七、补充说明

一、三种可行的消息压缩方案

消息压缩在WCF中的实现其实很简单,我们只需要在消息(请求消息/回复消息)被序列化之后,发送之前进行压缩;在接收之后,反序列化之前进行解压缩即可。针对压缩/解压缩使用的时机,我们具有三种典型的解决方案。

  • 通过自定义MessageEncoder和MessageEncodingBindingElement 来完成。具体的实现,可以参阅张玉彬的文章《WCF进阶:将编码后的字节流压缩传输》和MSDN的文章《Custom Message Encoder: Compression Encoder》。
  • 直接创建用于压缩和解压缩的信道,在CodePlex中具有这么一个WCF Extensions;
  • 自定义MessageFormatter实现序列化后的压缩和法序列化前的解压缩,这就是我们今天将要介绍的解决方案。

二、DataCompressor——用于数据压缩与解压缩组件

我们支持两种方式的压缩,Dflate和GZip。两种不同的压缩算法通过如下定义的CompressionAlgorithm枚举表示。

   1: public enum CompressionAlgorithm
   3:     GZip,
   5: }

而如下定义的DataCompressor负责基于上述两种压缩算法实际上的压缩和解压缩工作。

   3:     static byte[] Compress(byte[] decompressedData,CompressionAlgorithm algorithm)
   5:         using (MemoryStream stream = new MemoryStream())
   7:             if (algorithm == CompressionAlgorithm.Deflate)
   9:                 GZipStream stream2 = new GZipStream(stream,CompressionMode.Compress,true);
  11:                 stream2.Close();
  13:             else
  15:                 DeflateStream stream3 = new DeflateStream(stream,1)" id="lnum16">  16:                 stream3.Write(decompressedData,1)" id="lnum17">  17:                 stream3.Close();
  19:             return stream.ToArray();
  21:     }
  23:     byte[] Decompress(byte[] compressedData,1)" id="lnum24">  24:     {
  26:         {
  29:                 using (GZipStream stream2 =   30:                 {
  32:                 }
  34:             else
  36:                 using (DeflateStream stream3 =   37:                 {
  39:                 }
  41:         }
  43:? 
  45:     {
  47:         {
  49:             byte[] buffer = new byte[0x400];
  51:             {
  53:             }
  55:         }
  57: }

三、MessageCompressor——用于消息压缩与解压的组件

而针对消息的压缩和解压缩通过如下一个MessageCompressor来完成。具体来说,我们通过上面定义的DataCompressor对消息的主体部分内容进行压缩,并将压缩后的内容存放到一个预定义的XML元素中(名称和命名空间分别为CompressedBody和http://www.artech.com/comporession/),同时添加相应的MessageHeader表示消息经过了压缩,以及采用的压缩算法。对于解压缩,则是通过消息是否具有相应的MessageHeader判断该消息是否经过压缩,如果是则根据相应的算法对其进行解压缩。具体的实现如下:

2: {
   4:      {
   6:      }
   8:      {
  10:          using (XmlDictionaryReader reader1 = sourceMessage.GetReaderAtBodyContents())
  12:              buffer = Encoding.UTF8.GetBytes(reader1.ReadOuterXml());
  14:          if (buffer.Length == 0)
  16:              Message emptyMessage = Message.CreateMessage(sourceMessage.Version,(string)null);
  18:              sourceMessage.Properties.CopyProperties(sourceMessage.Properties);
  20:              return emptyMessage;
  22:          byte[] compressedData = DataCompressor.Compress(buffer,1)">this.Algorithm);
  24:          XmlTextReader reader = new XmlTextReader(new StringReader(copressedBody),1)">new NameTable());
  26:          message2.Headers.CopyHeadersFrom(sourceMessage);
  28:          message2.AddCompressionHeader(  29:          sourceMessage.Close();
  31:      }
  33:      public Message DecompressMessage(Message sourceMessage)
  35:          if (!sourceMessage.IsCompressed())
  37:              return sourceMessage;
  39:          CompressionAlgorithm algorithm = sourceMessage.GetCompressionAlgorithm();
  41:          byte[] compressedBody = sourceMessage.GetCompressedBody();
  43:          string newMessageXml = Encoding.UTF8.GetString(decompressedBody);
  45:          Message newMessage = Message.CreateMessage(sourceMessage.Version,reader2);
  47:          newMessage.Properties.CopyProperties(sourceMessage.Properties);
  49:      }
  51:      public CompressionAlgorithm Algorithm { get; private set; }
class CompressionUtil
   4:     string CompressionMessageBody = "CompressedBody";
   6:? 
   8:     {
  10:     }
  12:     void AddCompressionHeader(this Message message,CompressionAlgorithm algorithm)
  14:         message.Headers.Add(MessageHeader.CreateHeader(CompressionMessageHeader,Namespace,1)">string.Format("algorithm = "{0}"",algorithm)));
  16:? 
  19:         message.Headers.RemoveAll(CompressionMessageHeader,Namespace);
  21:? 
  23:     {
  25:         {
  27:             algorithm = algorithm.Replace("algorithm =",1)">string.Empty).Replace(""",1)">string.Empty).Trim();
  29:             {
  31:             }
  34:             {
  36:             }
  38:         }
  40:     }
  42:     byte[] GetCompressedBody(  43:     {
  45:         using (XmlReader reader1 = message.GetReaderAtBodyContents())
  47:             buffer = Convert.FromBase64String(reader1.ReadElementString(CompressionMessageBody,Namespace));
  49:         return buffer;
  51:? 
  53:     {
  55:         using (XmlWriter writer2 = XmlWriter.Create(output))
  57:             writer2.WriteStartElement(CompressionMessageBody,1)" id="lnum58">  58:             writer2.WriteBase64(content,content.Length);
  60:         }
  62:     }
class CompressionMessageFormatter: IDispatchMessageFormatter,IClientMessageFormatter
   4:? 
public MessageCompressor MessageCompressor { get;    8:? 
  10:     {
  12:         Type innerFormatterType = Type.GetType(DataContractSerializerOperationFormatterTypeName);
  14:         this.InnerClientMessageFormatter = innerFormatter as IClientMessageFormatter;
  16:     }
  18:     void DeserializeRequest(Message message,1)">object[] parameters)
  20:         message = this.MessageCompressor.DecompressMessage(message);
  22:     }
  24:     public Message SerializeReply(MessageVersion messageVersion,1)">object[] parameters,1)">object result)
  26:         var message = this.InnerDispatchMessageFormatter.SerializeReply(messageVersion,parameters,result);
  28:     }
  30:     object DeserializeReply(Message message,1)" id="lnum31">  31:     {
  35:? 
  38:         var message = this.InnerClientMessageFormatter.SerializeRequest(messageVersion,parameters);
   1: [AttributeUsage( AttributeTargets.Method)]
   3: {
   5:? 
   7:? 
   9:     {
  11:         clientOperation.DeserializeReply = true;
  13:         if (null == dataContractFormatAttribute)
  15:             dataContractFormatAttribute = new DataContractFormatAttribute();
  18:         var dataContractSerializerOperationBehavior = operationDescription.Behaviors.Find<DataContractSerializerOperationBehavior>();
void ApplyDispatchBehavior(OperationDescription operationDescription,DispatchOperation dispatchOperation)
  29:             dataContractFormatAttribute =   30:         }
  32:         dispatchOperation.Formatter =   33:     }
  35:     void Validate(OperationDescription operationDescription) { }
   1: [ServiceContract(Namespace= "http://www.artech.com/")]
   4:     [OperationContract]
double Add(double x,1)">double y);
   8: class CalculatorService : ICalculator
  10:     double y)
  12:         return x + y;
  14: }

我们采用BasicHttpBinding作为终结点的绑定类型(具体的配置请查看源代码),下面是通过Fiddler获取的消息的内容,它们的主体部分都经过了基于压缩的编码。

2: s:Header>
>7L0H...PAAAA//8=>

七、补充说明

由于CompressionMessageFormatter使用基于DataContractSerializer序列化器的DataContractSerializerOperationFormatter进行消息的序列化和发序列化工作。而DataContractSerializer仅仅是WCF用于序列化的一种默认的选择(WCF还可以采用传统的XmlSeriaizer)。为了让CompressionMessageFormatter能够使用其他序列化器,你可以对于进行相应的修正。

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读