You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 03:53:21