wcfazureselfhostedhttp-status-code-413

WCF 413 Request Entity Too Large - Self Hosted WebHttpBinding


There are many discussions about this problem, however I have now tried every possible solution and we are still getting 413 Request Entity Too Large errors from the server.

Our WCF service is self hosted via an Azure Worker role, and does not use IIS. All of our configuration is specified in code:

var host = new ServiceHost(searchEngine);

// Create binding
var binding = new WebHttpBinding(WebHttpSecurityMode.Transport);

binding.MaxReceivedMessageSize = 2147483647;
binding.MaxBufferSize = 2147483647;
binding.MaxBufferPoolSize = 2147483647;

var readerQuotas = new XmlDictionaryReaderQuotas
{
    MaxStringContentLength = 2147483647,
    MaxArrayLength = 2147483647,
    MaxBytesPerRead = 2147483647,
    MaxDepth = 2147483647,
    MaxNameTableCharCount = 2147483647
};

// Setting quotas on a BindingElement after the binding is created has no effect on that binding.
// See: https://stackoverflow.com/questions/969479/modify-endpoint-readerquotas-programatically
binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, readerQuotas, null);

binding.ReceiveTimeout = new TimeSpan(1, 0, 0);
binding.SendTimeout = new TimeSpan(1, 0, 0);

// Add the service endpoint
var ep = host.AddServiceEndpoint(
    typeof(ISearchEngine),
    binding,
    string.Format("https://{0}/SearchEngine", externalEndpoint));

ep.Behaviors.Add(new WebHttpBehavior());

// Increase the MaxItemsInObjectGraph quota for all operations in this service
foreach (var operation in ep.Contract.Operations)
{
    operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = 10000000;
}

return host;

And this is our client configuration - also specified in code:

var binding = new WebHttpBinding(WebHttpSecurityMode.Transport);

binding.MaxReceivedMessageSize = 2147483647;
binding.MaxBufferSize = 2147483647;
binding.MaxBufferPoolSize = 2147483647;

var readerQuotas = new XmlDictionaryReaderQuotas
{
    MaxStringContentLength = 2147483647,
    MaxArrayLength = 2147483647,
    MaxBytesPerRead = 2147483647,
    MaxDepth = 2147483647,
    MaxNameTableCharCount = 2147483647
};

// Setting quotas on a BindingElement after the binding is created has no effect on that binding.
// See: https://stackoverflow.com/questions/969479/modify-endpoint-readerquotas-programatically
binding.GetType().GetProperty("ReaderQuotas").SetValue(binding, readerQuotas, null);

binding.ReceiveTimeout = new TimeSpan(1, 0, 0);
binding.SendTimeout = new TimeSpan(1, 0, 0);

binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

var channelFactory = new ChannelFactory<ISearchEngine>(binding, endpointAddress);

channelFactory.Endpoint.Behaviors.Add(new WebHttpBehavior());


// Increase the MaxItemsInObjectGraph quota for all operations in this service
foreach (var operation in channelFactory.Endpoint.Contract.Operations)
{
    operation.Behaviors.Find<DataContractSerializerOperationBehavior>().MaxItemsInObjectGraph = 10000000;
}

return channelFactory.CreateChannel();

My only hunch could be a problem with the SSL connection? There are some articles mentioning a problem specific to IIS, however I'm not sure if this is relevant to self hosted services.

Any advice very much appreciated.

UPDATE:

To confirm my hunch that SSL was the problem, I temporarily disabled SSL and lo and behold the problem disappeared.

So now I need to figure out why SSL would be causing the problem. There is a fair bit of documentation about a similar problem, but it relates to IIS hosted services only (ours is self hosted from a windows service):

IIS7 - (413) Request Entity Too Large | uploadReadAheadSize

Would anyone out there know an equivalent setting that would apply to self hosted WCF services only?


Solution

  • I found the problem, thanks to this seemingly unrelated post:

    http://forums.newatlanta.com/messages.cfm?threadid=554611A2-E03F-43DB-92F996F4B6222BC0&#top

    It was absolutely an SSL issue, and it's to do with binding the SSL certificate to the port you are hosting on. You must bind the certificate using netsh and add clientcertnegotiation=enable to the binding.

    In our case we were already using netsh since we were using a different port, so our binding now looks like this:

    netsh http add sslcert ipport=0.0.0.0:10100 certhash=000000089A6679262D845B650FDDE5390F0D86AB appid={000007b4-2d4b-4587-ae99-7a6627476f76} clientcertnegotiation=enable
    

    For those of you hosting through IIS, and changing the value of UploadReadAheadSize, the forum post above notes that this may cause high CPU and instead this solution may be better.