如何在C#中使用GZIP压缩WCF服务响应?Web.config配置无效
WCF服务响应GZIP压缩实现方案
一、修正Web.config配置(最常用方式)
很多时候配置不生效是因为绑定类型选错、节点配置不全或者端点没关联正确的绑定。以下是针对不同绑定的正确配置:
1. 针对basicHttpBinding的配置
<system.serviceModel> <bindings> <basicHttpBinding> <binding name="GzipEnabledBinding" messageEncoding="Text"> <security mode="None"/> <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384"/> <compression enabled="true" /> <!-- 启用压缩 --> </binding> </basicHttpBinding> </bindings> <services> <service name="YourNamespace.YourWcfService"> <!-- 端点必须关联上面定义的GzipEnabledBinding --> <endpoint address="" binding="basicHttpBinding" bindingConfiguration="GzipEnabledBinding" contract="YourNamespace.IYourServiceContract"/> </service> </services> <behaviors> <serviceBehaviors> <behavior> <serviceMetadata httpGetEnabled="true"/> <serviceDebug includeExceptionDetailInFaults="false"/> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel>
2. 针对wsHttpBinding的配置
wsHttpBinding需指定messageEncoding为Text/Mtom,同时启用压缩:
<system.serviceModel> <bindings> <wsHttpBinding> <binding name="WsHttpGzipBinding" messageEncoding="Text"> <security mode="None"/> <compression enabled="true" /> </binding> </wsHttpBinding> </bindings> <services> <service name="YourNamespace.YourWcfService"> <endpoint address="" binding="wsHttpBinding" bindingConfiguration="WsHttpGzipBinding" contract="YourNamespace.IYourServiceContract"/> </service> </services> </system.serviceModel>
3. 自定义绑定场景
如果使用自定义绑定,需添加gzipMessageEncoding元素:
<customBinding> <binding name="CustomGzipBinding"> <gzipMessageEncoding innerMessageEncoding="textMessageEncoding"/> <httpTransport/> </binding> </customBinding>
二、自定义GZIP消息编码器(配置失效时的兜底方案)
若上述配置仍不生效(比如旧版WCF或特殊绑定场景),可自行实现消息编码器:
1. 编写GZip消息编码器及工厂
using System.IO; using System.IO.Compression; using System.ServiceModel.Channels; public class GZipMessageEncoder : MessageEncoder { private readonly MessageEncoder _innerEncoder; public GZipMessageEncoder(MessageEncoder innerEncoder) => _innerEncoder = innerEncoder; public override string ContentType => _innerEncoder.ContentType; public override string MediaType => _innerEncoder.MediaType; public override MessageVersion MessageVersion => _innerEncoder.MessageVersion; public override Message ReadMessage(Stream stream, int maxSizeOfHeaders, string contentType) { using var gzipStream = new GZipStream(stream, CompressionMode.Decompress, leaveOpen: true); return _innerEncoder.ReadMessage(gzipStream, maxSizeOfHeaders, contentType); } public override void WriteMessage(Message message, Stream stream) { using var gzipStream = new GZipStream(stream, CompressionMode.Compress, leaveOpen: true); _innerEncoder.WriteMessage(message, gzipStream); stream.Flush(); } public override Message ReadMessage(ArraySegment<byte> buffer, BufferManager bufferManager, string contentType) { var decompressedBuffer = DecompressBuffer(buffer, bufferManager); return _innerEncoder.ReadMessage(decompressedBuffer, bufferManager, contentType); } public override ArraySegment<byte> WriteMessage(Message message, int maxMessageSize, BufferManager bufferManager, int messageOffset) { var buffer = _innerEncoder.WriteMessage(message, maxMessageSize, bufferManager, messageOffset); return CompressBuffer(buffer, bufferManager, messageOffset); } private ArraySegment<byte> CompressBuffer(ArraySegment<byte> buffer, BufferManager bufferManager, int messageOffset) { using var memoryStream = new MemoryStream(); using var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, true); gzipStream.Write(buffer.Array, buffer.Offset, buffer.Count); var compressedBytes = memoryStream.ToArray(); var bufferedBytes = bufferManager.TakeBuffer(compressedBytes.Length + messageOffset); Array.Copy(compressedBytes, 0, bufferedBytes, messageOffset, compressedBytes.Length); bufferManager.ReturnBuffer(buffer.Array); return new ArraySegment<byte>(bufferedBytes, messageOffset, compressedBytes.Length); } private ArraySegment<byte> DecompressBuffer(ArraySegment<byte> buffer, BufferManager bufferManager) { using var memoryStream = new MemoryStream(buffer.Array, buffer.Offset, buffer.Count); using var gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress); using var outputStream = new MemoryStream(); gzipStream.CopyTo(outputStream); var decompressedBytes = outputStream.ToArray(); var bufferedBytes = bufferManager.TakeBuffer(decompressedBytes.Length); Array.Copy(decompressedBytes, 0, bufferedBytes, 0, decompressedBytes.Length); bufferManager.ReturnBuffer(buffer.Array); return new ArraySegment<byte>(bufferedBytes, 0, decompressedBytes.Length); } } public class GZipMessageEncoderFactory : MessageEncoderFactory { private readonly MessageEncoderFactory _innerFactory; public GZipMessageEncoderFactory(MessageEncoderFactory innerFactory) => _innerFactory = innerFactory; public override MessageEncoder Encoder => new GZipMessageEncoder(_innerFactory.Encoder); public override MessageVersion MessageVersion => _innerFactory.MessageVersion; }
2. 实现自定义绑定元素
using System.ServiceModel.Channels; public class GZipMessageEncodingBindingElement : MessageEncodingBindingElement { private readonly MessageEncodingBindingElement _innerBindingElement; public GZipMessageEncodingBindingElement(MessageEncodingBindingElement innerBindingElement) => _innerBindingElement = innerBindingElement; public override MessageEncoderFactory CreateMessageEncoderFactory() { return new GZipMessageEncoderFactory(_innerBindingElement.CreateMessageEncoderFactory()); } public override BindingElement Clone() { return new GZipMessageEncodingBindingElement(_innerBindingElement.Clone()); } public override T GetProperty<T>(BindingContext context) { return _innerBindingElement.GetProperty<T>(context) ?? base.GetProperty<T>(context); } public override MessageVersion MessageVersion { get => _innerBindingElement.MessageVersion; set => _innerBindingElement.MessageVersion = value; } }
3. 配置中启用自定义绑定
<system.serviceModel> <extensions> <bindingElementExtensions> <add name="gzipMessageEncoding" type="YourNamespace.GZipMessageEncodingBindingElement, YourAssemblyName"/> </bindingElementExtensions> </extensions> <bindings> <customBinding> <binding name="CustomGzipBinding"> <gzipMessageEncoding> <textMessageEncoding messageVersion="Soap11"/> </gzipMessageEncoding> <httpTransport/> </binding> </customBinding> </bindings> <services> <service name="YourNamespace.YourWcfService"> <endpoint address="" binding="customBinding" bindingConfiguration="CustomGzipBinding" contract="YourNamespace.IYourServiceContract"/> </service> </services> </system.serviceModel>
三、验证压缩是否生效
用Fiddler或浏览器开发者工具查看响应头,确认存在Content-Encoding: gzip,同时对比响应内容大小(压缩后应明显小于原内容)。
内容的提问来源于stack exchange,提问作者ADesai
相关产品推荐
相关产品推荐

