ASHX Download Large File

  • Thread starter Thread starter sequoyan
  • Start date Start date
S

sequoyan

Hello All - I have made an ASHX that sends a file of about 120MB to the
client but the save file dialog only appears after the entire file is
downloaded to the client. How can I make it appear before the download
instead? My goal is to give the user the normal file-download experience in
the browser - click link, immediate save file dialog, click save, download
progress dialog, success. Is this possible with ASHX?

Thanks for any help.

Thomas
 
I have made an ASHX that sends a file of about 120MB to the
client but the save file dialog only appears after the entire file is
downloaded to the client. How can I make it appear before the download
instead? My goal is to give the user the normal file-download experience in
the browser - click link, immediate save file dialog, click save, download
progress dialog, success. Is this possible with ASHX?

UPDATE:
I've implemented an custom handler in web.config so that the client now
requests a file of a madeup extension and the request is sent to my
IHttpHandler which looks like this basically:

Sub ProcessRequest(ByVal context As HttpContext) Implements
IHttpHandler.ProcessRequest
context.Response.ContentType = "application/zip"
context.Response.AddHeader("Content-Disposition", "attachment;
filename=" & Path.GetFileName(context.Request.FilePath))
context.Response.AddHeader("Content-Length", 1)
context.Response.StatusCode = 200
context.Response.End()
End Sub

This causes the save file dialog to appear as desired but I'm not sure how
to actually serve the file when the user clicks save on the dialog. How/where
does that request come in?

Cheers,
Thomas
 
The file must be sent in the same response you sending all header info.

BUT: You must
1. Set correct Content-Length. Right now you setting it to 1.
2. Disable Buffering in ASP.NET otherwise ASP.NET will allocate huge chunck
of memory for you file.

Something like this (i did not run it through compiler).
context.Response.ContentType = "application/zip"
context.Response.AddHeader("Content-Disposition", "attachment;
filename=myfile.txt")
context.Response.AddHeader("Content-Length", FileLenght)
context.Response.StatusCode = 200

context.Response.Buffer =- False
context.Response.Flush()
context.Response.WriteFile("C:\myfile.txt")
context.Response.End()


George.
 
The file must be sent in the same response you sending all header info.

I need to send it in parts because it is big.
BUT: You must
1. Set correct Content-Length. Right now you setting it to 1.

Corrected. See new code below.
2. Disable Buffering in ASP.NET otherwise ASP.NET will allocate huge chunck
of memory for you file.

Ok. See code below.

Sub ProcessRequest(ByVal context As HttpContext) Implements
IHttpHandler.ProcessRequest
context.Response.ContentType = "application/zip"
context.Response.AddHeader("Content-Disposition", "attachment;
filename=" & Path.GetFileNameWithoutExtension(F.FileName) & ".zip")
context.Response.AddHeader("Content-Length", F.Size)
context.Response.AddHeader("Last-Modified", New
DateTime(CLng(F.Timestamp)))
context.Response.AddHeader("Accept-Ranges", "bytes")
context.Response.AddHeader("ETag", "doesThisMatter")
context.Response.AddHeader("Server", "SMT Alentejo")
context.Response.AddHeader("Date", DateTime.UTCNow.ToString("r"))
context.Response.StatusCode = 200
context.Response.BufferOutput = False
context.Response.Flush()
End Sub

This brings up the save file dialog but again, when I click save I get no
further requests to the web server for the additional segments of the
download (206 requests).

_T
 
You simply can not do that. HTTP protocol does not allow that. You must send
file in the same request/respond.
You need to do all what you did and start sending file right after you did
context.Response.Flush()

That command will ensure that the header was sent to the browser and it
showed the 'save file' dialog and will not have to wait for all file to be
transmitted.

George.
 
You simply can not do that. HTTP protocol does not allow that. You must send
file in the same request/respond.
You need to do all what you did and start sending file right after you did
context.Response.Flush()

206/partial is supported by Http. I'm just not sure how to do it with .NET.
 
206 is for partial requests only.
Browsers do not support partial requests (as far as I know). The client must
ask for specific portion of the file and send 'Range' in a header request.


George.
 
206 is for partial requests only.
Browsers do not support partial requests (as far as I know). The client must
ask for specific portion of the file and send 'Range' in a header request.

I got the idea for 206s by using a packet sniffer to see what happens when I
user a browser to download a large file from a different server using a
normal A link.
 
For anyone that is curious here is what finally worked:

Sub ProcessRequest(ByVal context As HttpContext) Implements
IHttpHandler.ProcessRequest

Dim ext As String =
Path.GetExtension(context.Request.FilePath).ToLower

Select Case ext
Case ".jpg", ".png", ".gif", ".tif", ".tga", ".bmp"
context.Response.ContentType = "image/" & Replace(ext, ".",
"")
Case Else
context.Response.ContentType = "application/" & Replace(ext,
".", "")
End Select

context.Response.AddHeader("Content-Disposition", "attachment;
filename=" & Path.GetFileName(context.Request.FilePath))
context.Response.AddHeader("Content-Length", <FileSizeHere>)
context.Response.AddHeader("Last-Modified", <FileDateHere>)
context.Response.AddHeader("Accept-Ranges", "bytes")
context.Response.AddHeader("ETag", "ThisDoesntSeemToMatter")
context.Response.AddHeader("Date", DateTime.UTCNow.ToString("r"))
context.Response.StatusCode = 200

context.Response.Flush()

context.Response.BufferOutput = False
'Copy data to context.Response.OutputStream
End Sub
 
Back
Top