Downloading a file raises exception

3

I have a webform with a GridView which has filename as a column. If you click on filename, an Open/Save dialog box is presented to the user. Most of time, this raises an exception with the error message - The remote host closed the connection. The error code is 0x80072746.

This error is not visible to the users in any other browser, except Firefox. In Firefox, the selected file gets rendered on the page itself, and after sometime, the page gives an error - The connection was reset.

I am downloading the file by breaking it down to packets as I have to identify if file has been completely downloaded or not, and then write this entry to database table.

I have put Buffer="false" in the page directive, but it does not work. I tried removing Response.Flush() from my code, but to no avail.

My file download code is as follows:

LinkButton btnTemp = (LinkButton)sender;
GridViewRow row = (GridViewRow)btnTemp.NamingContainer;
HiddenFieldFullFileName.Value = row.Cells[1].Text;

FileInfo file = new FileInfo(HiddenFieldFullFileName.Value);
if (file.Exists)
{
    string filePath="", fileName="";

    //store filepath and filename in separate variables
    string[] temp = row.Cells[1].Text.Split('\\');
    for (int j = 0; j < temp.Length; j++)
    {
        if (j < (temp.Length - 1))
            if(j==0)
              filePath = filePath + temp[j];
            else
              filePath = filePath + "\\" + temp[j];
        else
            fileName = temp[j];

    }
    FileStream myFile = new FileStream(row.Cells[1].Text, FileMode.Open,FileAccess.Read, FileShare.ReadWrite);

    //Reads file as binary values
    BinaryReader _BinaryReader = new BinaryReader(myFile);

    long startBytes = 0;
    string lastUpdateTimeStamp = File.GetLastWriteTimeUtc(filePath).ToString("r");
    string _EncodedData = HttpUtility.UrlEncode(fileName, Encoding.UTF8) + lastUpdateTimeStamp;

    //Clear the content of the response
    Response.Clear();
    Response.Buffer = false;
    Response.AddHeader("Accept-Ranges", "bytes");
    Response.AppendHeader("ETag", "\"" + _EncodedData + "\"");
    Response.AppendHeader("Last-Modified", lastUpdateTimeStamp);

    //Set the ContentType
    Response.ContentType = "application/octet-stream";

    //Add the file name and attachment,
    //which will force the open/cancel/save dialog to show, to the header
    Response.AddHeader("Content-Disposition", "attachment;filename=" + file.Name);

    //Add the file size into the response header
    Response.AddHeader("Content-Length", (file.Length - startBytes).ToString());
    Response.AddHeader("Connection", "Keep-Alive");

    //Set the Content Encoding type
    Response.ContentEncoding = Encoding.UTF8;

    //Send data
    _BinaryReader.BaseStream.Seek(startBytes, SeekOrigin.Begin);

    //Dividing the data in 1024 bytes package
    int maxCount = (int)Math.Ceiling((file.Length - startBytes + 0.0) / 1024);

    //Download in block of 1024 bytes
    int i;
    for (i = 0; i < maxCount && Response.IsClientConnected; i++)
    {
        Response.BinaryWrite(_BinaryReader.ReadBytes(1024));
        Response.Flush();
    }

    //compare packets transferred with total number of packets
    if (i >= maxCount)
    {
        //get the IP address of user
        string ipAddress = HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];
        if (ipAddress == null)
        {
            ipAddress = HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
        }

        //write the download information to database table

    }


    //Close Binary reader and File stream
    _BinaryReader.Close();
    myFile.Close();
}

What is the source of the problem?

c#
asp.net
exception
asked on Stack Overflow Jul 25, 2011 by KhD • edited Jul 25, 2011 by VMAtm

2 Answers

2

The remote host closed the connection. The error code is 0x80072746. - This exception is raised if browser didn't finish the downloading before your server end the connection.

This can be because of your strange scheme of writing the file and sql after your Response.BinaryWrite.

If you want to create some custom server for downloading, you should also create custom client - browser don't know anything about your code, and he can lose his connection.
Also, your check about transferred bytes makes no sense - you can't know about bytes accepted by client.

So I strongly recommend Response.WriteFile(filename).

answered on Stack Overflow Jul 25, 2011 by VMAtm
1

I think you can just use Response.WriteFile, and you should use the FileInfo object you already created. Code:

        LinkButton btnTemp = (LinkButton)sender;
        GridViewRow row = (GridViewRow)btnTemp.NamingContainer;
        HiddenFieldFullFileName.Value = row.Cells[1].Text;

        FileInfo file = new FileInfo(HiddenFieldFullFileName.Value);
        if (file.Exists)
        {

            string lastUpdateTimeStamp = file.LastWriteTimeUtc.ToString("r");
            string _EncodedData = HttpUtility.UrlEncode(file.Name, Encoding.UTF8) + lastUpdateTimeStamp;

            //Clear the content of the response
            Response.Clear(); 
            Response.AppendHeader("ETag", "\"" + _EncodedData + "\"");
            Response.AppendHeader("Last-Modified", lastUpdateTimeStamp);

            //Set the ContentType
            Response.ContentType = "application/octet-stream"; 

            //Add the file name and attachment,
            //which will force the open/cancel/save dialog to show, to the header
            Response.AddHeader("Content-Disposition", "attachment;filename=" + file.Name); 

            //Send data
            Response.WriteFile(file.FullName);
            Response.End();
        }

If you know the specific contenttype then instead of "application/octet-stream" you can change that to the mimetype of your file (see here for examples)

answered on Stack Overflow Jul 25, 2011 by Willem • edited Jul 25, 2011 by Willem

User contributions licensed under CC BY-SA 3.0