WCF客户端GZIP压缩配置疑问:代码位置与请求自动压缩实现
Hey there! Let's break this down step by step to get your WCF client sending compressed requests and handling compressed responses properly, fitting right into your existing code setup.
1. Where to add request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate?
In WCF, you can't directly tweak the underlying HttpWebRequest from the generated client proxy out of the box. Instead, you'll need to create a custom endpoint behavior that attaches a configured WebRequestHandler to handle response decompression. Here's how to do it:
First, add this helper behavior class to your client project:
using System.Net; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; public class DecompressionBehavior : IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { var handler = new WebRequestHandler(); handler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate; bindingParameters.Add(new HttpClientHandlerProperty(handler)); } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } }
Then, update your client call code to attach this behavior before making the request:
using (ServiceReference1.Srv1Client client = new ServiceReference1.Srv1Client()) { // Attach the decompression behavior to auto-unpack GZip/Deflate responses client.Endpoint.Behaviors.Add(new DecompressionBehavior()); var data = client.GetData(longText, file); }
This tells the underlying HTTP client to automatically decompress compressed responses from your IIS server.
2. How to make client requests (all parameters) automatically use GZip compression?
WCF doesn't include built-in request compression for BasicHttpBinding, so we'll add a custom message inspector to compress the request body before sending it, plus set the right HTTP header so IIS knows to decompress it.
First, add this message inspector and its associated behavior:
using System.IO; using System.IO.Compression; using System.ServiceModel; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Dispatcher; using System.Xml; public class GzipRequestInspector : IClientMessageInspector { public object BeforeSendRequest(ref Message request, IClientChannel channel) { // Create a buffered copy of the original message to work with var buffer = request.CreateBufferedCopy(int.MaxValue); var originalMessage = buffer.CreateMessage(); // Compress the message body var ms = new MemoryStream(); using (var gzipStream = new GZipStream(ms, CompressionMode.Compress, true)) { var writer = XmlDictionaryWriter.CreateBinaryWriter(gzipStream); originalMessage.WriteMessage(writer); writer.Flush(); } // Build the compressed message ms.Position = 0; var compressedMessage = Message.CreateMessage( request.Version, request.Headers.Action, XmlDictionaryReader.CreateBinaryReader(ms, XmlDictionaryReaderQuotas.Max) ); // Copy over all original headers foreach (var header in request.Headers) { compressedMessage.Headers.Add(header); } // Set the Content-Encoding header so IIS recognizes the compressed request var httpRequestProperty = new HttpRequestMessageProperty(); httpRequestProperty.Headers["Content-Encoding"] = "gzip"; compressedMessage.Properties[HttpRequestMessageProperty.Name] = httpRequestProperty; request = compressedMessage; return null; } public void AfterReceiveReply(ref Message reply, object correlationState) { } } // Behavior to attach the compression inspector to the client public class GzipRequestBehavior : IEndpointBehavior { public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MessageInspectors.Add(new GzipRequestInspector()); } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } }
Now, update your client code to include both behaviors:
using (ServiceReference1.Srv1Client client = new ServiceReference1.Srv1Client()) { // Handle decompressing incoming responses client.Endpoint.Behaviors.Add(new DecompressionBehavior()); // Compress outgoing requests client.Endpoint.Behaviors.Add(new GzipRequestBehavior()); var data = client.GetData(longText, file); }
Quick Notes to Keep in Mind
- Double-check your IIS configuration to ensure it's set up to accept compressed requests (you already enabled dynamic compression, but confirm that
Content-Encoding: gzipis allowed for your WCF endpoints). - Large payloads (like your
filebyte array) will see the biggest performance gains from compression—smaller data might not get a huge boost, but it won't cause harm. - If you prefer config files over code, you can register these behaviors in your client's
app.configinstead, but the code approach is simpler for one-off client setups.
内容的提问来源于stack exchange,提问作者DooDoo

