Async HttpHandlers + file downloading in chunks

  • Thread starter Thread starter Omikron
  • Start date Start date
O

Omikron

Hi,
I have a problem with downloading large files from the server (approx.
1gb) using http. When around 180mb is downloaded I am getting
timeouts. Files are downloaded in chunks using Response.BinaryWrite
method. I've read that in such situations Asynchronous Http handlers
may come in
rescue. Unfortunetly Msdn doesn't have many examples of their usage.
According to http://msdn.microsoft.com/en-us/library/ms227433.aspx
when it comes to the download in the aspx page I have:

Dim obj_DownloadAsyncHttpHandler As New DownloadFileAsyncHandler()
obj_DownloadAsyncHttpHandler.BeginProcessRequest(Context, Nothing,
obj_AsyncHttpHandlerParameters)

and:

Public Class DownloadFileAsyncHandler
Implements IHttpAsyncHandler

Public Function BeginProcessRequest(ByVal context As
System.Web.HttpContext, ByVal cb As System.AsyncCallback, ByVal
extraData As Object) As System.IAsyncResult Implements
System.Web.IHttpAsyncHandler.BeginProcessRequest

Dim asynch As New DownloadAsynchOperation(cb, context,
extraData)
..........
context.Response.Clear()
context.Response.ClearHeaders()
context.Response.AddHeader("Content-Type", "application/octet-
stream")
context.Response.AddHeader("Content-Length",
intFileSize.ToString())
context.Response.AddHeader("Content-Disposition", "attachment;
filename=" & strFileName)
context.Response.ContentType = "application/octet-stream"
context.Response.Flush()

asynch.StartAsyncWork()
Return asynch
End Function

Class DownloadAsynchOperation
Implements IAsyncResult

Public Sub StartAsyncWork()
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf
StartAsyncTask), Nothing)
End Sub

Private Sub StartAsyncTask(ByVal workItemState As [Object])
................
'writting file chunks here
While intTotalBytesRead < intFileSize
If (Not _context.Response.IsClientConnected) Then
Exit While
End If

Dim async_ChunkDownloadCompleted As New AsyncCallback(AddressOf
ChunkDownloadCompleted)
fileChunk = objFileDownloadHelper.DownloadFileChunk
(filenameWithPath, intTotalBytesRead, size)

If fileChunk IsNot Nothing AndAlso fileChunk.Length > 0 Then
intTotalBytesRead += size
_context.Response.OutputStream.BeginWrite(fileChunk, 0,
fileChunk.Length, async_ChunkDownloadCompleted, Nothing)
End If
End While
......
End Sub

Private Sub ChunkDownloadCompleted(ByVal ar As System.IAsyncResult)
_context.Response.OutputStream.EndWrite(ar)
_context.Response.Flush()
End Sub

I've managed to run this succesfully only once (don't even know how).
Most of the time when it comes to first BeginWrite method call,
standard box to save a file appears but in the meantime I am getting
error "Server cannot flush a completed response." in
ChunkDownloadCompleted or that context.Response.IsClientConnected is
null :( context and _context are from the aspx page responsible for
downloading. Do you have any ideas why it fails ?

Many thanks
Bartek
 
your async code will not work. you start a background thread to write to
file, but do not stall the request thread to wait for it to complete. so
the original request completes and closes the connection. in general if
you use a background worker thread, it should not access request,
response, context or session as these are released when page processing
completes.

your original problem was request timing out. set Server.ScriptTimeout
to something greater tan 60 seconds.

if you have many users will will need to bumpup worker thread counts, or
they will get server busy.

-- bruce (sqlwork.com)

Hi,
I have a problem with downloading large files from the server (approx.
1gb) using http. When around 180mb is downloaded I am getting
timeouts. Files are downloaded in chunks using Response.BinaryWrite
method. I've read that in such situations Asynchronous Http handlers
may come in
rescue. Unfortunetly Msdn doesn't have many examples of their usage.
According to http://msdn.microsoft.com/en-us/library/ms227433.aspx
when it comes to the download in the aspx page I have:

Dim obj_DownloadAsyncHttpHandler As New DownloadFileAsyncHandler()
obj_DownloadAsyncHttpHandler.BeginProcessRequest(Context, Nothing,
obj_AsyncHttpHandlerParameters)

and:

Public Class DownloadFileAsyncHandler
Implements IHttpAsyncHandler

Public Function BeginProcessRequest(ByVal context As
System.Web.HttpContext, ByVal cb As System.AsyncCallback, ByVal
extraData As Object) As System.IAsyncResult Implements
System.Web.IHttpAsyncHandler.BeginProcessRequest

Dim asynch As New DownloadAsynchOperation(cb, context,
extraData)
..........
context.Response.Clear()
context.Response.ClearHeaders()
context.Response.AddHeader("Content-Type", "application/octet-
stream")
context.Response.AddHeader("Content-Length",
intFileSize.ToString())
context.Response.AddHeader("Content-Disposition", "attachment;
filename=" & strFileName)
context.Response.ContentType = "application/octet-stream"
context.Response.Flush()

asynch.StartAsyncWork()
Return asynch
End Function

Class DownloadAsynchOperation
Implements IAsyncResult

Public Sub StartAsyncWork()
ThreadPool.QueueUserWorkItem(New WaitCallback(AddressOf
StartAsyncTask), Nothing)
End Sub

Private Sub StartAsyncTask(ByVal workItemState As [Object])
...............
'writting file chunks here
While intTotalBytesRead < intFileSize
If (Not _context.Response.IsClientConnected) Then
Exit While
End If

Dim async_ChunkDownloadCompleted As New AsyncCallback(AddressOf
ChunkDownloadCompleted)
fileChunk = objFileDownloadHelper.DownloadFileChunk
(filenameWithPath, intTotalBytesRead, size)

If fileChunk IsNot Nothing AndAlso fileChunk.Length > 0 Then
intTotalBytesRead += size
_context.Response.OutputStream.BeginWrite(fileChunk, 0,
fileChunk.Length, async_ChunkDownloadCompleted, Nothing)
End If
End While
.....
End Sub

Private Sub ChunkDownloadCompleted(ByVal ar As System.IAsyncResult)
_context.Response.OutputStream.EndWrite(ar)
_context.Response.Flush()
End Sub

I've managed to run this succesfully only once (don't even know how).
Most of the time when it comes to first BeginWrite method call,
standard box to save a file appears but in the meantime I am getting
error "Server cannot flush a completed response." in
ChunkDownloadCompleted or that context.Response.IsClientConnected is
null :( context and _context are from the aspx page responsible for
downloading. Do you have any ideas why it fails ?

Many thanks
Bartek
 
Back
Top