[Source: http://geekswithblogs.net/EltonStoneman]
BizTalk 2006 R2 ships with WCF adapters and pre-configured settings for common bindings – basicHttp and wsHttp being typically used for SOAP messaging. With a static port you can use the WCF-Custom adapter, select an existing binding and configure it further in the UI, with the full set of binding options available to you:
Here I’m using basicHttp, but I’ve configured the maxReceivedMessageSize, sendTimeout and transferMode settings to allow us to call long-running WCF services which return large responses.
In a dynamic port, you’re limited to the settings you can configure, as the WCF Adapter Property Schema doesn’t contain the full set of binding properties. You can set the sendTimeout and maxReceivedMessageSize on an outgoing message using code:
port(Microsoft.XLANGs.BaseTypes.TransportType) = “WCF-BasicHttp”;
requestMessage(WCF.MaxReceivedMessageSize) = 104857600;
requestMessage(WCF.SendTimeout) = “00:10:00”;
– but there’s no way to access less common properties like transferMode if you’re using this approach. Originally this is how we were configuring our outgoing messages, using SSO to store the values used for the binding properties (see Receiving large WCF response messages in ESB Guidance), but we soon ran into an issue with one of the BizTalk servers running out of memory when attempting to process a large WCF response message:
System.InsufficientMemoryException: Failed to allocate a managed memory buffer of 104857600 bytes. The amount of available memory may be low. —> System.OutOfMemoryException: Exception of type ‘System.OutOfMemoryException’ was thrown.
at System.ServiceModel.Diagnostics.Utility.AllocateByteArray(Int32 size)
For basicHttp, the transferMode setting allows you to specify that messages should be streamed (one way or both ways), or buffered – the default is buffered, so when we receive the response message, although it will be streamed in the BizTalk stack, it is completely loaded into memory by the WCF stack. Note that WCF is trying to allocate the full value specified in maxReceivedMessageSize – 100 Mb – even though we’ve set this as a practical maximum, and the actual incoming message was half that size.
To remedy it, I’ve switched to using the WCF-Custom transport, and specifying basicHttp with my additional settings in the BindingConfiguration property:
port(Microsoft.XLANGs.BaseTypes.TransportType) = “WCF-Custom”;
requestMessage(WCF.BindingType) = “basicHttpBinding”;
requestMessage(WCF.BindingConfiguration) = “<binding name=\”basicHttpBinding\” sendTimeout=\”00:10:00\” maxReceivedMessageSize=\”104857600\” />”;
The BindingType needs to be specified in addition to the configuration. For the BindingConfiguration value, the Properties page for a static WCF-Custom port allows you to export the settings, so you can configure it in the UI and then save the XML representation, rather than coding it all by hand.
By shifting the BindingConfiguration value to the SSO config store, we’ll have the full range of WCF configuration available to change at run-time, so a switch to using wsHttp or netTcp bindings is just a setting change using the SSO Config Tool, and a change to the endpoint address (which we configure in UDDI in this case). Originally I wanted finer control over what could be configured, so we could limit changes to a known set of properties. But having tried this approach I prefer it – it means switching bindings and adding or changing any settings can easily be done without modifying the solution – and I’ll be recommending it as best practice.