Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Streaming large file uploads to ASP.NET MVC

For an application I'm working on, I need to allow the user to upload very large files--i.e., potentially many gigabytes--via our website. Unfortunately, ASP.NET MVC appears to load the entire request into RAM before beginning to service it--not exactly ideal for such an application. Notably, trying to circumvent the issue via code such as the following:

if (request.Method == "POST")
{
    request.ContentLength = clientRequest.InputStream.Length;
    var rgbBody = new byte[32768];

    using (var requestStream = request.GetRequestStream())
    {
        int cbRead;
        while ((cbRead = clientRequest.InputStream.Read(rgbBody, 0, rgbBody.Length)) > 0)
        {
            fileStream.Write(rgbBody, 0, cbRead);
        }
    }
}

fails to circumvent the buffer-the-request-into-RAM mentality. Is there an easy way to work around this behavior?

like image 832
Benjamin Pollack Avatar asked Jun 25 '09 20:06

Benjamin Pollack


People also ask

How do I handle large uploads?

Possible solutions: 1) Configure maximum upload file size and memory limits for your server. 2) Upload large files in chunks. 3) Apply resumable file uploads. Chunking is the most commonly used method to avoid errors and increase speed.

How can upload video in ASP NET MVC?

Right-click on project Add select New Folder, name it VideoFileUpload to upload all the audio files in that folder. Right-click on Models folder, select Add, then select Class. A window will appear. Choose Class, give it the name VideoFiles, then click on Add.

What is the maximum file size for file upload in ASP NET?

Large file uploads in ASP.NET. Uploading files via the FileUpload control gets tricky with big files. The default maximum filesize is 4MB - this is done to prevent denial of service attacks in which an attacker submitted one or more huge files which overwhelmed server resources.

How do I upload a file in ASP NET MVC?

ASP.NET MVC actions support uploading of one or more files using simple model binding for smaller files or streaming for larger files. Uploading small files with model binding. To upload small files, you can use a multi-part HTML form or construct a POST request using JavaScript.

How to upload large files with streaming?

Streaming large files is covered in the Upload large files with streaming section. To upload small files, use a multipart form or construct a POST request using JavaScript. JavaScript's ( Fetch API) is used to submit the form's data.

How do I send large files to an MVC/web-API server?

Sending large files to an MVC/Web-API Server can be problematic. This article is about an alternative. The approach used is to break a large file up into small chunks, upload them, then merge them back together on the Server via file transfer by partitioning.


2 Answers

It turns out that my initial code was basically correct; the only change required was to change

request.ContentLength = clientRequest.InputStream.Length;

to

request.ContentLength = clientRequest.ContentLength;

The former streams in the entire request to determine the content length; the latter merely checks the Content-Length header, which only requires that the headers have been sent in full. This allows IIS to begin streaming the request almost immediately, which completely eliminates the original problem.

like image 83
Benjamin Pollack Avatar answered Oct 03 '22 10:10

Benjamin Pollack


Sure, you can do this. See RESTful file uploads with HttpWebRequest and IHttpHandler. I have been using this method for a few years and have a site that has been tested with files of at least several gigabytes. Essentially, you want to create your own IHttpHandler, which is easier than it sounds.

In a nutshell, you create a class that implements the IHttpHandler interface, meaning you have to support the IsReusable property and the ProcessRequest method. On top of that, there is a minor change to your web.config, and it works like a charm. At this stage in the life cycle of the request, the entire file being uploaded does not get loaded into memory, so it neatly steps around out of memory issues.

Note that in the web.config,

<httpHandlers>
 <add verb="*" path="DocumentUploadService.upl" validate="false" type="TestUploadService.FileUploadHandler, TestUploadService"/>
</httpHandlers>

the file referenced, DocumentUploadService.upl, doesn't actually exist. That is just there to give an alternate extension so that the request is not intercepted by the standard handler. You point your file upload form to that path, but then your FileUploadHandler class kicks in and actually receives the file.

Update: Actually, the code I use is different from that article, and I think I stumbled on the reason it works. I use the HttpPostedFile class, in which "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."

if (context.Request.Files.Count > 0)
{
    string tempFile = context.Request.PhysicalApplicationPath;
    for(int i = 0; i < context.Request.Files.Count; i++)
    {
        HttpPostedFile uploadFile = context.Request.Files[i];
        if (uploadFile.ContentLength > 0)
        {
            uploadFile.SaveAs(string.Format("{0}{1}{2}",
              tempFile,"Upload\\", uploadFile.FileName));
        }
    }
}
like image 27
D'Arcy Rittich Avatar answered Oct 04 '22 10:10

D'Arcy Rittich