Resolving XmlDictionaryReaderQuotas Error for WCF Compression using GZipEncoder with Custom Binding
To compress the WCF data transfered over the wire, Microsoft Samples contains a GZipEncoder. This encoder wraps TextMessagingEncoder applying GZip Compression on top of it (N.B. you can even wrap a Binary Encoder to enable compression on Images for instance).
But as you try to transfer a large object using GZipEncoder, you will run into the below error asking to increase maximum string length content:
Unhandled Exception: System.ServiceModel.CommunicationException: Error in deserializing body of reply message for operation ‘GetData’. The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader. Line 192, position 30. — System.Xml.XmlException: The maximum string content length quota (8192) has been exceeded while reading XML data. This quota may be increased by changing the MaxStringContentLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader.
This can look quite confusing if you are not familiar with how WCF Channel pipeline works. This error is encountered by many even if you are not using GZipEncoder outlined above. So let’s look at all solutions while using & not using GzipEncoder (below I set the limit to max allowed, though it’s not recommended) :
1) Standard Binding (No GZipEncoder)
<bindings>
<basicHttpBinding>
<binding>
<readerQuotas maxStringContentLength=”2147483647″/>
</binding>
</basicHttpBinding>
</bindings>
//new BasicHttpBinding().ReaderQuotas.MaxStringContentLength = Int32.MaxValue
N.B. Binding is a collection of channels providing an abstract way to add readerQuotas.
2) Custom Binding (No GZipEncoder)
<bindings>
<customBinding>
<binding>
<textMessageEncoding>
<readerQuotas maxStringContentLength=”2147483647″/>
</textMessageEncoding>
<httpTransport />
</binding>
</customBinding>
</bindings>
/*
CustomBinding binding = new CustomBinding();
TextMessageEncodingBindingElement element = new TextMessageEncodingBindingElement();
element.ReaderQuotas.MaxStringContentLength = Int32.MaxValue;
binding.Elements.Add(element);
…
*/
N.B. For CustomBinding you need to select channels manually and for encoding channel you can specify the readerQuotas.
3) Using GZipEncoder – in this case you need to add couple of lines in GZipMessageEncodingBindingElement class (GZipMessageEncodingBindingElement.cs file). The method which you would change is below:
public override IChannelFactory BuildChannelFactory (BindingContext context)
{
if (context == null)
throw new ArgumentNullException(“context”);
context.BindingParameters.Add(this);
var property = GetProperty<XmlDictionaryReaderQuotas>(context);
property.MaxStringContentLength = 2147483647; //Int32.MaxValue
property.MaxArrayLength = 2147483647;
property.MaxBytesPerRead = 2147483647;
return context.BuildInnerChannelFactory();
}
N.B. It’s not possible to alter these parameters through configuration file while using GZipEncoder.
Hope this helps
.
[...] WCF Compression via HTTPS I had blogged some time earlier about making GZipCompression work for large messages over WCF. Though GZipCompression reduces the overall size of message, [...]
Pingback by Securing WCF Compression via HTTPS « Niraj Bhatt - Architect’s Blog | April 8, 2009 |
[...] – WCF’s extensible channel architecture allows us to plug-in a compression channel. So, how about not using MTOM or binary, and just applying compression on what we are above to [...]
Pingback by MTOM vs. Streaming vs. Compression – Large attachments over WCF « Niraj Bhatt – Architect’s Blog | August 3, 2009 |