10 January 2011

Sending Large Files via BizTalk to WCF Service

Recently I was doing some data load tests on my orchestration, which transforms the data and calls a WCF service. I was given over 200 data files and dumped them in to the receive folder. The majority of them worked but a handful of them didn't and I noticed the offending files had much bigger file sizes. The event log error on the BizTalk server looked like this:

Microsoft.XLANGs.Core.XlangSoapException: An error occurred while processing the message, refer to the details section for more information
Message ID: {8E01C976-5029-4C9C-A11C-BF37E3DED66F}
Instance ID: {B573495A-A1BD-49E0-B84B-00DE3EB6AB04}
Error Description: System.ServiceModel.CommunicationException: An error occurred while receiving the HTTP response to http://localhost:3500/DataService.svc/DataService.
This could be due to the service endpoint binding not using the HTTP protocol.
This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down).
See server logs for more details.
---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive.
---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
...

This seemed to indicate an issue on the web server hosting the WCF services. So I enabled tracing in the web.config:

<system.diagnostics>
<sources>
<source name="System.ServiceModel" switchValue="Warning">
<listeners>
<add name="WCFTrace" />
</listeners>
</source>
</sources>

<sharedListeners>
<add name="WCFTrace" type="System.Diagnostics.TextWriterTraceListener" initializeData="C:/Logs/Trace.txt" />
</sharedListeners>
</system.diagnostics>

and tried again and the trace log wrote this:

<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Error">
<TraceIdentifier>http://msdn.microsoft.com/en-AU/library/System.ServiceModel.Diagnostics.TraceHandledException.aspx</TraceIdentifier>
<Description>Handling an exception.</Description>
<AppDomain>fbd928cd-22-129391837330249458</AppDomain>
<Exception>
<ExceptionType>System.ServiceModel.CommunicationException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>Maximum request length exceeded.</Message>
<StackTrace>at System.ServiceModel.Activation.HostedHttpRequestAsyncResult.GetInputStream()
...

Some Googling of this error suggests to modify the WCF service's web.config file to include this:

<system.web>
<httpRuntime maxRequestLength="2147483647"/>

So I tried again. Still didn't work but the trace log had a different error:

<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Error">
<TraceIdentifier>http://msdn.microsoft.com/en-AU/library/System.ServiceModel.Diagnostics.ThrowingException.aspx</TraceIdentifier>
<Description>Throwing an exception.</Description>
<AppDomain>fbd928cd-27-129391852361919458</AppDomain>
<Exception>
<ExceptionType>System.ServiceModel.ProtocolException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>The maximum message size quota for incoming messages (65536) has been exceeded. To increase the quota, use the MaxReceivedMessageSize property on the appropriate binding element.</Message>
<StackTrace>at System.ServiceModel.Channels.HttpInput.ThrowHttpProtocolException(String message, HttpStatusCode statusCode, String statusDescription)
...

So following the error message's suggestion, I modified the WCF service's web.config file to specify the binding's maxReceivedMessageSize parameter (the WCF service I am calling is using the basicHttpBinding):

<bindings>
<basicHttpBinding>
<binding maxReceivedMessageSize="2147483647">
...

So again I tried, and again another error in the WCF trace log:

<TraceRecord xmlns="http://schemas.microsoft.com/2004/10/E2ETraceEvent/TraceRecord" Severity="Error">
<TraceIdentifier>http://msdn.microsoft.com/en-AU/library/System.ServiceModel.Diagnostics.ThrowingException.aspx</TraceIdentifier>
<Description>Throwing an exception.</Description>
<AppDomain>fbd928cd-24-129391843506509458</AppDomain>
<Exception>
<ExceptionType>System.ServiceModel.Dispatcher.NetDispatcherFaultException, System.ServiceModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</ExceptionType>
<Message>The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://xxx. The InnerException message was 'Maximum number of items that can be serialized or deserialized in an object graph is '65536'. Change the object graph or increase the MaxItemsInObjectGraph quota. '. Please see InnerException for more details.</Message>
<StackTrace>at System.ServiceModel.Dispatcher.DataContractSerializerOperationFormatter.DeserializeParameterPart(XmlDictionaryReader reader, PartInfo part, Boolean isRequest)
...

So again I modified the WCF service's web.config file to fix this issue:

<system.serviceModel>
...
<behaviors>
<serviceBehaviors>
<behavior>
<dataContractSerializer maxItemsInObjectGraph="2147483647"/>
...

and voila, the WCF service is invoked and BizTalk receives the expected response back. Hope this saves you some time.