title: Transferring large files: combining streamed transfer and content-length
body: <p>TL;DR: How can I stream large files with a known size using WCF, and still show progress (<code>Content-Length</code>) to the final user (a web browser)?</p>
  
  <p>I have a WCF REST service which downloads and then serves very large files (1-20Gb) to a web browser. To simplify, think of my service as a proxy. This obliges me to set <code>TransferMode = Streamed</code> or <code>TransferMode = StreamedResponse</code> on the Binding, or the end client will have to wait for the source files to be downloaded to the webserver before the actual download begins. Also, buffered transfer mode kills the server for large files (RAM usage). Intermediate disk storage is not an option. From <a href="http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&amp;l=EN-US&amp;k=k%28System.ServiceModel.WebHttpBinding.TransferMode%29;k%28TargetFrameworkMoniker-.NETFramework,Version=v4.5%29;k%28DevLang-csharp%29&amp;rd=true" rel="nofollow noreferrer">TransferMode</a> man page:</p>
  
  <blockquote>
    <p><a href="http://msdn.microsoft.com/query/dev11.query?appId=Dev11IDEF1&amp;l=EN-US&amp;k=k%28System.ServiceModel.WebHttpBinding.TransferMode%29;k%28TargetFrameworkMoniker-.NETFramework,Version=v4.5%29;k%28DevLang-csharp%29&amp;rd=true" rel="nofollow noreferrer">(...)</a>  Buffered transfers hold the entire message in a memory buffer until
    the transfer is complete.</p>
  </blockquote>
  
  <p>But when setting <code>TransferMode</code> to <code>Streamed</code> or <code>StreamedResponse</code>, WCF no longer returns the header <code>Content-length</code> to the client, and a new header <code>Transfer-Encoding: chunked</code> is added. This is consistent with <a href="http://en.wikipedia.org/wiki/Chunked_transfer_encoding" rel="nofollow noreferrer">wikipedias article</a> on chunked transfer:</p>
  
  <blockquote>
    <p>(...) uses the Transfer-Encoding HTTP header <em>in place</em> of the Content-Length
    header (...)</p>
  </blockquote>
  
  <p>But I always know the size of the data to be transferred beforehand, and for the end user, it's very frustrating not to know the size of the download. So:</p>
  
  <p>(How) can I configure the WCF binding to use a "streaming" Transfer mode (more specifically, <em>not</em> buffering the entire message before sending) and still use the <code>Content-Length</code> header? </p>
  
  <p>Some leads:</p>
  
  <ul>
  <li><p><a href="https://stackoverflow.com/questions/3304126/chunked-encoding-and-content-length-header">This q/a</a> states that the http standard disallows both <code>Transfer-Encoding</code> and <code>Content-length: 123456</code> in the same message, so I guess that's not an option? </p></li>
  <li><p>I have tried modifying the headers using an inspector in <a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.idispatchmessageinspector.beforesendreply%28v=vs.110%29.aspx" rel="nofollow noreferrer">IDispatchMessage.BeforeSendReply</a> but at this point the <code>Content-Length</code> header has not yet been removed, and <code>Transfer-Encoding</code> has not yet been set, so it's "too early". I have later read that chunked transfer encoding is on TCP level, so changing the header at this point probably wont work even if I could.</p></li>
  <li><p>I have tried setting <a href="http://msdn.microsoft.com/en-us/library/system.servicemodel.servicehostingenvironment.aspnetcompatibilityenabled%28v=vs.110%29.aspx" rel="nofollow noreferrer">aspNetCompatibilityEnabled</a><code>="true"</code>, setting wcf transfer mode to buffered output (default) and then set <code>System.Web.HttpContext.Current.Response.BufferOutput = false;</code>. This is ignored by wcf though, the message is clearly buffered.</p></li>
  <li><p>It seems to be a missing feature, according to <a href="https://connect.microsoft.com/VisualStudio/feedback/details/366324/support-non-chunked-streamed-responses-on-wcf-httptransport#details" rel="nofollow noreferrer">this link</a>. But there may still be a quirky workaround somewhere..</p></li>
  </ul>