Unable to set ReaderQuotas for BasicHttpBinding generated in code
I have a project with requirements to generate a single executable file with no dependencies that will automate the submission of data to a WCF service based on command line parameters passed to it. As a result, I cannot configure the WCF binding and quotas in an App.config file, so I am generating a BasicHttpBinding
in code to use when dimensioning the WCF client object.
However, the WCF service accepts the binary data for a relatively small Excel spreadsheet that ends up being around 30kb, so the default configuration settings for the binding's ReaderQuotas
are inadequate. My attempts to increase them in code to 1MB, however, have met with failure each time I make a call to the service.
I have attempted to set the binding in the following two ways, first in the constructor itself:
Private theBinding As New BasicHttpBinding With {
.SendTimeout = TimeSpan.FromMinutes(1),
.OpenTimeout = TimeSpan.FromMinutes(1),
.CloseTimeout = TimeSpan.FromMinutes(1),
.ReceiveTimeout = TimeSpan.FromMinutes(10),
.AllowCookies = False,
.BypassProxyOnLocal = False,
.HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
.MessageEncoding = WSMessageEncoding.Text,
.TransferMode = TransferMode.Buffered,
.UseDefaultWebProxy = True,
.MaxBufferSize = 1048576,
.MaxReceivedMessageSize = 1048576,
.ReaderQuotas = New XmlDictionaryReaderQuotas With {
.MaxDepth = 32,
.MaxStringContentLength = 8192,
.MaxArrayLength = 1048576,
.MaxBytesPerRead = 4096,
.MaxNameTableCharCount = 16384
}
}
And also by removing the ReaderQuotas
setter in the above code and setting it to max values using System.Reflection
on form load. I realize this method is more for bindings that have been created in a config file and are 开发者_如何转开发therefore typically immutable, but I figured it couldn't hurt to try:
theBinding.GetType.GetProperty("ReaderQuotas").SetValue(theBinding, XmlDictionaryReaderQuotas.Max, Nothing)
The WCF client is dimensioned using the final overload for WCF client constructors:
Using theClient As New WCFServiceClient(theBinding, theEndpoint)
...
End Using
However, I still receive the following exception when making a call to the WCF client:
System.ServiceModel.ProtocolException: The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:theObject. The InnerException message was 'There was an error deserializing the object of type RootNameSpace.ObjectType. The maximum array length quota (16384) has been exceeded while reading XML data. This quota may be increased by changing the MaxArrayLength property on the XmlDictionaryReaderQuotas object used when creating the XML reader. Line 1, position 46272.'. Please see InnerException for more details.
Head is meeting desk. Could really use some guidance for what I may have missed here when it comes to properly configuring reader quotas.
Check your service's configuration file (if it has one) or the settings on the binding its using. It's possible the client is sending the message just fine but the service is rejecting it because it's still using the default values.
As suggested by Tim, the solution to this issue was to configure the IIS service endpoint correctly to read large messages, not just the client. Since I didn't happen across readily available/accurate/thorough information on doing this, I am reproducing my solution here for those who follow.
First, configure a basic HTTP binding with the appropriate reader quota settings as follows:
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="basicHttpBinding_IMyService" maxReceivedMessageSize="2147483647">
<readerQuotas maxDepth="32" maxArrayLength="2147483647" maxStringContentLength="2147483647"
maxBytesPerRead="4096" maxNameTableCharCount="16384" />
</binding>
</basicHttpBinding>
</bindings>
<system.serviceModel>
The important fields to consider are the values of the maxArrayLength
and maxStringcontentLength
attributes for the readerQuotas
as well as the maxReceivedMessageSize
attribute for the binding
. I have set them to max values–I believe–in this example, but in my actual implementation I chose a value of 1MB (1048576) instead. Set your values as you feel most appropriate for your service. Then specify an endpoint for your contract using the binding configuration you have just generated:
<system.serviceModel>
<services>
<service>
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicHttpBinding_IMyService"
contract="RootNamespace.IMyService" />
</service>
</services>
<system.serviceModel>
Note that it was not necessary to set the address of the endpoint in my case. It is worth mentioning that I am targeting the .NET 4.0 Framework and have multiple site bindings enabled in my hosting environment with <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
. Your mileage may vary.
精彩评论