Niraj Bhatt – Architect's Blog

Ruminations on .NET, Architecture & Design

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 :) .

About these ads

9 responses to “Resolving XmlDictionaryReaderQuotas Error for WCF Compression using GZipEncoder with Custom Binding

  1. Pingback: Securing WCF Compression via HTTPS « Niraj Bhatt - Architect’s Blog

  2. Pingback: MTOM vs. Streaming vs. Compression – Large attachments over WCF « Niraj Bhatt – Architect’s Blog

  3. Pingback: May 2010 be your Best Year so far!!! « Niraj Bhatt – Architect’s Blog

  4. Y.Ramesh February 23, 2010 at 11:05 am

    If we are creating binding programmatically we need to set the buffers in the following manner.

    BasicHttpBinding binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport);
    binding.MaxReceivedMessageSize = int.MaxValue;
    binding.ReaderQuotas.MaxArrayLength = int.MaxValue;
    binding.ReaderQuotas.MaxBytesPerRead = int.MaxValue;
    binding.ReaderQuotas.MaxDepth = int.MaxValue;
    binding.ReaderQuotas.MaxNameTableCharCount = int.MaxValue;
    binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;

  5. Ben Fulton November 2, 2010 at 8:42 pm

    Thanks for posting this – very useful!

  6. Birgen May 24, 2011 at 4:17 am

    Thanks for the solution!

  7. Birgen May 25, 2011 at 12:28 am

    Hi,

    I added the quotas. It works fine when I get data from the WCf service, but when I send data to the WCF Service, then I still receive the MaxArrayLength exception.

    Any thoughts?

    • Keith P July 27, 2011 at 8:41 pm

      You need to increase the ReaderQuotas of the custom gzip binding in your web.config….change your custombinding section to look something like this:

  8. Pingback: Silverlight WCF で大きいデータを送受信するときの設定解除方法 | The Structural Engine

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 171 other followers

%d bloggers like this: