通过WCF扩展实现消息压缩
对于需要进行大规模数据传输的WCF应用来说,对于请求消息和回复消息进行传输前的压缩,不但可以降低网络流量,也可以提高网络传输的性能。由于WCF的扩展性,我们可以采用不同的方式实现对消息的压缩,本文提供一种比较简单的实现方式。[源代码从这里下载]
一、三种可行的消息压缩方案消息压缩在WCF中的实现其实很简单,我们只需要在消息(请求消息/回复消息)被序列化之后,发送之前进行压缩;在接收之后,反序列化之前进行解压缩即可。针对压缩/解压缩使用的时机,我们具有三种典型的解决方案。
二、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能够使用其他序列化器,你可以对于进行相应的修正。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
- 如何在Web项目中给没有添加API核心组件添加APIController的
- asp.net – HttpCookie.Expire时区含义?
- asp.net-mvc – Asp.Net MVC Razor FileUpload Html Helper
- asp.net-mvc – 无法在mvc 4中映射特定控制器的路由
- asp.net 文件上传实例汇总
- asp.net-mvc – 如何在ASP.NET MVC控制器中读取GlobalResou
- asp.net – 在.NET中使用TinyMCE有一种简单的Spellcheck方法
- ASP.Net(也许是MVC)网站的博客引擎
- asp.net-mvc – 从扩展Apicontroller的MVC控制器返回Json
- asp.net – 如何在WebPage中显示嵌入的Excel文件?
- asp.net – 使用ASP:文本框作为
- asp.net-mvc-3 – MVC默认重定向错误页面并不总是
- asp.net – 如何在GridView中隐藏TemplateField列
- asp.net-mvc – 是否可以在IIS服务器上部署asp.n
- asp.net – WCF数据服务还是只是WCF服务?
- asp.net-mvc – 使用Html.BeginForm与querystrin
- asp.net-mvc – 为什么我的动作方法不会超时?
- asp.net-mvc – 有没有人使用史蒂夫·桑德森的Mv
- asp.net-core – .net core(csproj)global.json’
- asp.net-mvc-4 – 如何为Web API控制器方法指定C