1

My question is similar to this post but I have to do the same using IIS, ASP.NET, and C#.

None of the methods in the HttpResponse class provide feedback if the data was sent or not, TransmitFile() just does its job (or not) and does not provide any means of knowing the result.

I was thinking of using the .Filter property but then again, the filter is based on the HttpResponseStream which does also not provide any feedback.

Any ideas?

Community
  • 1
  • 1
Hefaistos68
  • 381
  • 3
  • 9

2 Answers2

1

After some testing I came up with the following solution to the problem. TransmitFile() has one serious limitation: it reads the whole file into memory before sending, this is really bad for larger files. So basically I resorted to manual chunking and checking if the client is connected after each chunk.

context.Response.Clear();
context.Response.BufferOutput = false;
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + originalFilename);
context.Response.AddHeader("Content-Length", fileLength.ToString());
context.Response.Cache.SetNoStore();

context.Response.Flush();

downloadFailed = !context.Response.IsClientConnected;

int thisChunk;
long offset = 0;
int chunkSize = 1024 * 8;
byte[] bytes = new byte[chunkSize];

FileStream r = File.OpenRead(localFilename);

while((offset < fileLength) && !downloadFailed)
{
    if((fileLength - offset) < chunkSize)
    {
        thisChunk = (int)(fileLength - offset);
    }
    else
    {
        thisChunk = chunkSize;
    }

    r.Read(bytes, 0, chunkSize);

    try
    {
        context.Response.BinaryWrite(bytes);
        context.Response.Flush();

        if(!context.Response.IsClientConnected)
        {
            downloadFailed = true;
        }
    }
    catch(ObjectDisposedException ex1)
    {
        // Stream is closed, nothing written
        break;
    }
    catch(System.IO.IOException ex3)
    {
        // I/O error, unknown state, abort
        Trace.Write(ex3);
        break;
    }

    offset += thisChunk;
}

if(!downloadFailed)
{
    // now update the file, statistics, etc
}

context.Response.Flush();

HttpContext.Current.ApplicationInstance.CompleteRequest();

Will need to play a bit with the chunk size to find the optimal size. But basically it works reliably like this.

Hefaistos68
  • 381
  • 3
  • 9
0

Check Response.IsClientConnected after calling TransmitFile.

SLaks
  • 868,454
  • 176
  • 1,908
  • 1,964
  • Nope, none of the "writer" functions do throw exceptions. The only way to know if the client is still listening is using Response.IsClientConnected as mentioned below. – Hefaistos68 Feb 18 '10 at 12:40