Note that there are some explanatory texts on larger screens.

plurals
  1. POWCF HttpTransport: streamed vs buffered TransferMode
    text
    copied!<p>I have a self-hosted WCF service (v4 framework) that is exposed through a <code>HttpTransport</code>-based custom binding. The binding uses a custom <code>MessageEncoder</code> that is pretty much a <code>BinaryMessageEncoder</code> with the addition of gzip compression functionality.</p> <p>A Silverlight and a Windows client consume the web service.</p> <p><strong>Problem</strong>: in some cases the service had to return very large objects and occasionally threw OutOfMemory exceptions when responding to several concurrent requests (even if Task Manager reported ~600 Mb for the process). The exception happened in the custom encoder, when the message was about to be compressed, but I believe this was just a symptom and not the cause. The exception stated "failed to allocate x Mb" where x was 16, 32 or 64, not a overly huge amount -for this reason I believe something else already put the process near some limit before that.</p> <p>The service endpoint is defined as follows:</p> <pre><code>var transport = new HttpTransportBindingElement(); // quotas omitted for simplicity var binaryEncoder = new BinaryMessageEncodingBindingElement(); // Readerquotas omitted for simplicity var customBinding = new CustomBinding(new GZipMessageEncodingBindingElement(binaryEncoder), transport); </code></pre> <p>Then I did an experiment: I changed <code>TransferMode</code> from <code>Buffered</code> to <code>StreamedResponse</code> (and modified the client accordingly). This is the new service definition:</p> <pre><code>var transport = new HttpTransportBindingElement() { TransferMode = TransferMode.StreamedResponse // &lt;-- this is the only change }; var binaryEncoder = new BinaryMessageEncodingBindingElement(); // Readerquotas omitted for simplicity var customBinding = new CustomBinding(new GZipMessageEncodingBindingElement(binaryEncoder), transport); </code></pre> <p><strong>Magically, no OutOfMemory exceptions anymore</strong>. The service is a bit slower for small messages, but the difference gets smaller and smaller as message size grows. The behavior (both for speed and OutOfMemory exceptions) is reproducible, I did several tests with both configurations and these results are consistent.</p> <p>Problem solved, BUT: I cannot explain myself what is happening here. My surprise stems from the fact that <strong>I did not change the contract in any way</strong>. I.e. I did not create a contract with a single <code>Stream</code> parameter, etc., as you usually do for streamed messages. I am still using my complex classes with the same DataContract and DataMember attribute. <em>I just modified the endpoint</em>, that's all.</p> <p>I thought that setting TransferMode was just a way to <em>enable</em> streaming for properly formed contracts, but obviously there is more than that. Can anybody explain what actually happens under the hood when you change <code>TransferMode</code>?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload