3

In late testing phase i noticed an issue my application has sending files larger than 2 gigs (Int32.MaxValue). Is there an easy way to remedy this ? These are large high def .mov movie files. I used a Response.WriteFile in my controller to ensure the browser doesn't open any of the files (most are large video files that aren't opened by the browser but not all) and force the download as well as do some logging.

Right now my only option is to use ajax to do javascript based logging and link directly to the large mov files but i would like to avoid changing my logging methods so late in the development process. and would have really liked all the links to use one method of logging whether they are large mov files or files that need to be sent using writefile so the browser doesn't open them for simplicity sake. but it seems i have dont have much choice.

What is the logic behind preventing large file transfers like this ? In the stack trace i see everywhere Int64 size not Int32 so why is it not working ?

I am using latest(?) MVC (4.5.2) and VS2015.

This is the error i get when i request a large file:

[ArgumentOutOfRangeException: The size parameter must be between zero and the maximum Int32 value.
Parameter name: size
Actual value was 4563025348.]
   System.Web.HttpFileResponseElement..ctor(String filename, Int64 offset, Int64 size, Boolean isImpersonating, Boolean useTransmitFile, Boolean supportsLongTransmitFile) +3824261
   System.Web.HttpWriter.WriteFile(String filename, Int64 offset, Int64 size) +119
   System.Web.HttpResponse.WriteFile(String filename, Boolean readIntoMemory) +359
   System.Web.HttpResponseWrapper.WriteFile(String filename) +30

And this is the relevant part of my controller code

Response.AddHeader("Content-Disposition", "attachment;filename=" + filename);
Response.WriteFile(filePath);
Response.End();

Thank you

N.

Edit: Final code looks like this:

    using (FileStream fs = new FileStream(serverPath, FileMode.Open))
        {
            byte[] buffer = new byte[4096];
            int count = 0;

            Response.AddHeader("Content-Disposition", "attachment;filename=" + filename);
            while ((count = fs.Read(buffer, 0, buffer.Length)) > 0)
            {
                Response.OutputStream.Write(buffer, 0, count);
                Response.Flush();
            }
        }

HttpContext.ApplicationInstance.CompleteRequest();
Narcil
  • 325
  • 2
  • 13

1 Answers1

3

whats normally done is this case is that file is downloaded using streams. So that at any point in time the whole of the file(2GB!) is not loaded into memory. Think what amount of memory this would require if only 100 users request the file at the same time.

Whats you should do instead is get the file by reading it by a stream (FileStream) and write this stream directly to the response of the user.

Something like this

//assuming you have your FileStream handle already - named fs
byte[] buffer = new byte[4096];
long count = 0;

while ((count = fs.Read(buffer, 0, buffer.Length)) > 0)
{
    response.OutputStream.Write(buffer, 0, count);
    response.Flush();
}

See this answer - Write PDF stream to response stream

Community
  • 1
  • 1
Parv Sharma
  • 12,581
  • 4
  • 48
  • 80
  • please help me with the downvote. tell me whats the problem. tell me how can i solve it. tell me somethign – Parv Sharma Sep 07 '15 at 20:06
  • lol, i did not downvote you mate. some *** must have. here have an upvote :) i'm testing it as we speak will report asap. – Narcil Sep 07 '15 at 20:13
  • 1
    i get cannot convert long to int on the count param when calling the write method. – Narcil Sep 07 '15 at 20:29
  • Seems to work like a charm. Currently downloading a 4gig file from my local machine hope this works as well on the prod server which i don't have access from here. Thanks! – Narcil Sep 07 '15 at 21:00