Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternatives to Response.TransmitFile()

So I have the set of code I've been toying with for the past couple days, I need to download a file from the server to the client. That's the easy part, but I also need to refresh a grid view after it's finished and display in an alert that the file has been successfully created, but every way that I've found to download contains a select line of code which will be my downfall.

Response.End()

Response.Close() or

ApplicationInstance.CompleteRequest()

All of these end the current response or I believe in ApplicationInstance's case it flushes all the source code of the page to the text file I'm attempting to download. Following this is the snippet of code I have for downloading a file from the server, following is the source for downloading my file. If you have anything that can help solve this never ending nightmare it'd be greatly appreciated.

            //I brought everything together in an arraylist to write to file.
            asfinalLines = alLines.ToArray(typeof(string)) as string[];

            string FilePath = HttpContext.Current.Server.MapPath("~/Temp/");
            string FileName = "test.txt";

            // Creates the file on server
            File.WriteAllLines(FilePath + FileName, asfinalLines);

            // Prompts user to save file
            System.Web.HttpResponse response = System.Web.HttpContext.Current.Response;
            response.ClearContent();
            response.Clear();
            response.ContentType = "text/plain";
            response.AppendHeader("Content-Disposition", "attachment; filename=" + FileName + ";");
            response.TransmitFile(FilePath + FileName);
            response.Flush();

            // Deletes the file on server
            File.Delete(FilePath + FileName);

            response.Close();
like image 297
General Charismo Avatar asked Oct 31 '22 17:10

General Charismo


1 Answers

Approach 1: Using a temporary file
If you just want to delete the file after the file transfer or perform some other clean up operations you may do this

// generate you file
// set FilePath and FileName variables
string stFile = FilePath + FileName;
try {
    response.Clear();
    response.ContentType = "text/plain";
    response.AppendHeader("Content-Disposition", "attachment; filename=" + FileName + ";");
    response.TransmitFile(stFile);
    response.Flush();
} catch (Exception ex) {
    // any error handling mechanism
} finally {
    if (System.IO.File.Exists(stFile)) {
        System.IO.File.Delete(stFile);
    }
    HttpContext.Current.ApplicationInstance.CompleteRequest();
}

Approach 2: Without saving file to the server
If your text data is small then you may follow another (DO NOT use this approach for large data transfers), you can directly deliver the context as text file to the clients without saving them on to the server

try {
    // assuming asFinalLines is a string variable
    Response.Clear();
    Response.ClearHeaders();
    Response.AddHeader("Content-Length", asFinalLines.Length.ToString());
    Response.ContentType = "text/plain";
    response.AppendHeader("Content-Disposition", "attachment; filename=" + FileName + ";");
    Response.Write(asFinalLines);
    response.Flush();
} catch (Exception ex) {
    Debug.Print(asFinalLines);
} finally {
    HttpContext.Current.ApplicationInstance.CompleteRequest();
}

PS: I am a VB.NET person, tried to convert the code above in c# it may have some case-sensitivity issues but the logic is crystal clear

UPDATE:

Approach 3: Executing other code with file transfer.
It must be kept in mind that you can not have multiple responses to one request. You can NOT update your page and transmit a file in a single response. The headers can be set only once per request.

In this case you have to follow this methodology:

  • Create a new Div/Label where you will display a link to the file for download. Keep it hidden by default.
  • Process the request
  • Generate the required file (do NOT transmit yet, only save to server)
  • Perform other tasks, update your front end (i.e. refresh grid, display message etc) and also
  • Provide a link to the generated file in the hidden Label and show it. (You can also use your message div to provide the download link.
  • On download request from the link displayed in previous step transmit the file and then delete it as mentioned in Approach 1 (do NOT regenerate, only transmit/delete).
  • Alternatively you can delete old file before processing and generating new file. In this way you can allow the user to download the old file until a new file is generated. This method is better suitable for large files.

This approach adds an additional step for downloading the file after generating and does not support direct data transmission i.e. without saving it to the server.

like image 53
haraman Avatar answered Nov 11 '22 11:11

haraman