Search code examples
c#javascriptasp.netdownloadresponse

Download file to client PC and post back to page


I have a web page which returns a set of results which you can then ask for in a .csv format.

As the creation of the file is quite lengthy (at times up to 30 minutes), I have added some JavaScript that adds a class to a div so that it covers the screen, to tell users that the report is being created and to be patient.

After the file has been created and downloaded I would like the div to then return to its original state of not being there (so to speak).

Here is what I currently have.

JavaScript

function skm_LockScreen() {
    var lock = document.getElementById('ctl00_ContentPlaceHolder1_skm_LockPane');
    var lock2 = document.getElementById('ctl00_ContentPlaceHolder1_pleaseWait');
    if (lock)
        lock.className = 'LockOn';
    if (lock2)
        lock2.className = 'WaitingOn';
}
function skm_UnLockScreen() {
    var lock = document.getElementById('ctl00_ContentPlaceHolder1_skm_LockPane');
    var lock2 = document.getElementById('ctl00_ContentPlaceHolder1_pleaseWait');
    if (lock)
        lock.className = 'LockOff';
    if (lock2)
        lock2.className = 'WaitingOff';
}

Button

<asp:Button ID="LatestReportButton" runat="server" CssClass="standardButton" Text="Latest Quote Report" Width="140px"
OnClick="ReportButton_Click" CommandArgument="2" OnClientClick="skm_LockScreen()" />

Code behind

protected void ReportButton_Click(object sender, EventArgs e)
    {
        Page.ClientScript.RegisterStartupScript(base.GetType(), "unlock", "<script type=\"text/javascript\">skm_UnLockScreen();</script>");
        try
        {
            //Start creating the file
            using (StreamWriter sw = new StreamWriter(tempDest + "\\" + csvGuid + ".csv", true))
            {
                //Code to create the file goes 
            }
        }
        catch
        {
        }
        Response.AddHeader("Content-disposition", "attachment; filename=report.csv");
        Response.ContentType = "application/octet-stream";
        Response.WriteFile("CreatedReport.csv");
        Response.End();
    }

The issue I'm having is that the JavaScript is never written back to the page because of the Response.End();

I've already done it as two buttons, one to create the report the other to download it, but my company would prefer it to be all in one.

Any suggestions?


Solution

  • Given the length of time needed to generate the report, the method you're proposing contains a number of inherent risks, each of which will cause the report creation to fail:

    • the user may accidentally close the browser / tab;
    • the browser / tab might crash;
    • timeouts may occur on the web server.

    I would tackle this problem in a different way. In the first instance, I would look to see if the report generation can be optimized - "30 minutes" rings alarm bells immediately. Assuming database(s) are involved at some point, I would investigate the following as a minimum:

    • Are database indexes being used, or used correctly?
    • Do the report generation queries contain inefficient operations (CURSORs, for example)?
    • Do the execution plans reveal any other flaws in the report generation process?

    If this isn't a option (let's assume you can't modify the DBs for whatever reason), I would still consider a totally different approach to generating the report, whereby the report creation logic is moved outside of the web application into, say, a console app.

    For this, you would need to define:

    • a way to pass the report's parameters to the report generation app;
    • a way to identify the user that requested the report (ideally login credentials, or Windows identity);
    • a way to notify the user when the report is ready (email, on-screen message);
    • a directory on the server where the reports will be saved and downloaded from;
    • a separate page from which the user can download the report.

    A couple of database tables should be sufficient to log this information.