Search code examples
asp.net-mvcuploadhttppostedfilebase

Why doesn't HttpPostedFile perform as advertised and buffer downloads to disk rather than memory?


I am uploading large files to an ASP.NET server using a standard HTML <input> control posting multipart-form data. This is an ASP.NET MVC application.

According to MSDN, the HttpPostedFile class buffers to disk out of the box:

"Files are uploaded in MIME multipart/form-data format. By default, all requests, including form fields and uploaded files, larger than 256 KB are buffered to disk, rather than held in server memory."

I assume this means that when I access HttpPostedFileBase in my controller, that when I access the HttpPostedFileBase's InputStream property, I can write the file buffer somewhere without having to worry about the server running out of memory, which is obviously an unworkable solution.

Here's a bit of pseudocode for how I'm handling each of the incoming files from HttpPostedFileBase.

for(var i = 0; i< Request.Files.Count;i++)
{
    var fileBase = Request.Files[i];
    if (fileBase.ContentLength == 0)
    {
        continue;
    }

    // One thread per file
    ThreadPool.QueueUserWorkItem(state =>
    {
        // Read from fileBase.InputStream
    }, 
    null);
}

My web.config's httpRuntime block looks like this:

<httpRuntime
  executionTimeout="1200"
  requestLengthDiskThreshold="2097151"
  maxRequestLength="2097151"
  useFullyQualifiedRedirectUrl="false"
  minFreeThreads="8"
  minLocalRequestFreeThreads="4"
  appRequestQueueLimit="100" />

My implementation works, multiple files are uploaded as expected, except that the same amount of memory required to buffer the entire payload is consumed by the server. I have to assume that the InputStream is buffering everything. When I upload more files than I have memory, it predictably crashes with an OutOfMemoryException. Here's an image of the memory spike when uploading an 800mb file.

alt text

I know I could use a Flash/Silverlight widget or write a custom HttpModule to intercept uploads and handle them myself, but the current requirement would work flawlessly if HttpPostedFile did what MSDN says it does (or I'm doing it wrong).


Solution

  • why do you set

    requestLengthDiskThreshold="2097151"
    

    in the configuration? Doesn't that force the server to keep all uploads in RAM rather than buffering to disk?