tags:

views:

194

answers:

4
+4  A: 

This line:

lblEmpl.Visible = True

Never gets hit because this line:

Response.End()

Throws a ThreadAbortException

I think a cleaner way to handle this is to create a simple HttpHandler component, and 'open' it in a popup window. (The popup window shouldn't actually open. In most cases the browser will realize it's actually a download, and will suppress the tab/window.)

Research the IHttpHandler interface. They're actually quite simple to implement.

Here's a sample handler. Sorry it took awhile, I got called into a meeting:

public class CensusHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        string fileName = String.Format(
            CultureInfo.CurrentUICulture,
            "E_{0:00}{1:00}.csv",
            DateTime.Today.Month,
            DateTime.Today.Day
            );

        context.Response.ContentType = "text/csv";
        context.Response.AddHeader(
            "Content-Disposition", String.Format(null, "attachment; filename={0}", fileName)
            );

        //Dump the CSV content to context.Response

        context.Response.Flush();
    }

    public bool IsReusable { get { return false; } }
}

OK, try adding a javascript onclick event to trigger the download:

<asp:Button ID="Clickety" runat="server" Text="Click Me!" OnClick="Clickety_Click"
    OnClientClick="window.open('Handler.ashx', 'Download');" />

The regular OnClick event will fire your postback code. The javascript onclick (OnClientClick) event will launch the download via the HttpHandler.

Toby
What if I dont put the Response.End line there what will the effect be. Is there a downside?
Nick LaMarca
Even if I comment the Response.End line out it still doesnt work.
Nick LaMarca
Im searching the net and am not sure what you mean. I never used HttpHandler before. Can you point me to a good example?
Nick LaMarca
How do I use that thing. I have no idea, I have been researching these handlers and am totally lost.
Nick LaMarca
Try this. Add a "Generic Handler" item to your web app, and use the above code. Where I have the `Dump the CSV...` comment, put in `context.Response.WriteLine("Hello World!");` Now open the .ashx module in a browser and follow what happens.
Toby
I see that, it does the download and puts "Hello World" in the file but how do I hook it up to what I am trying to do. I have an aspx page that has 7 buttons on it (1 for each download) also on that page are labels next to the buttons labeled "download that are not visible. When someone clicks a button I want it to download the file (which this does) then make the label visible next to the button downloaded to notify the user that they downloaded this file. I am not sure how to hook this up or how it even helps make that happen?
Nick LaMarca
+1  A: 

You are sending the CSV down the Response Stream and then ending it. Therefore, once all of your code has run, the page itself is now no longer being sent down the Response Stream and so not updated in the browser.

In order to achieve what you are after you need to create a second response stream. The easiest way to do this is via a new browser window / popup. Then your CSV can download in the popup and your initial page response can remain in the initial browser.

Robin Day
Do you have a code sample of that?
Nick LaMarca
A: 

Just create a new page with this code on Page_Load

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) 
    Dim emplTable As DataTable = SiteAccess.DownloadEmployee_H()
    Dim d As String = Format(Date.Now, "d")
    Dim ad() As String = d.Split("/")
    Dim fd As String = ad(0) & ad(1)
    Dim fn As String = "E_" & fd & ".csv"
    Response.ContentType = "text/csv"
    Response.AddHeader("Content-Disposition", "attachment; filename=" & fn)
    CreateCSVFile(emplTable, Response.Output)
    Response.Flush()
    Response.End()
End Sub

Then on your original page make you lblEmpl invisible and the register a script like the following to open a new window with your csv.

var csvPageJS = string.Format("window.open ('{0}','mywindow');", ResolveUrl("~/MyCSVPage.aspx"));
  ClientScript.RegisterStartupScript(typeof(Page), "popup", csvPageJS, true);
alejandrobog
I tried that it doesnt work. It will download the data, but not refresh the controls on the page.
Nick LaMarca
I edit my answer, did you try it with the JS script
alejandrobog
That code kinda works. The only problem is it updates the page before making the label visible then opens the dialog. eventhough I said to make the label visible after the script is run. Dim csvPageJS As String = String.Format("window.open ('{0}','mywindow');", ResolveUrl("~/TESTLOAD.aspx")) ClientScript.RegisterStartupScript(GetType(Page), "popup", csvPageJS, True) lblRG.Visible = True
Nick LaMarca
Try using an updatepanel so you dont notice the page loading, just make sure you change ClientScript.RegisterStartupScript for ScriptManager.RegisterStartupScript to make it work with the async postback
alejandrobog
+1  A: 

You should go with a pop-up so you can still set your label on the original page. From what I see you could do something like this

  1. Create a seprate form for the pop-up to create the CSV, move your function to the load of the new page.cs and send it a querystring parm for its dataID to export.

    Protected Sub onLoad()
        Dim recordID As Integer = Request.Querystring("dID")
        Dim emplTable As DataTable = Nothing 
        Select Case recordID 
          case 1: emplTable = SiteAccess.DownloadEmployee_H() 
          case 2: emplTable = SiteAccess.DownloadManagers() 
        End Select 
        Response.Clear()
        Response.ContentType = "text/csv"
        Response.AddHeader("Content-Disposition", "attachment; filename=" & fn)
        CreateCSVFile(emplTable, Response.Output)
        Response.Flush()
        Response.End() 
        lblEmpl.Visible = True
    End Sub
    
  2. Launch your pop-up from the onClientClick property of the button, or register a script on the postback.

    function fnPopUpCSV(expType)
    {        
    window.open('/popUpPage.aspx?dID=' + expType,'CSVwindow', 
    'width=300,height=200,menubar=yes,status=yes,
    location=yes,toolbar=yes,scrollbars=yes');
    }
    
    
    <asp:Button ID="btnGenEmplCSV" runat="server" Text="Generate Employee CSV"
    onClientClick="javascript:return fnPopUpCSV(1);" />
    
    
    <asp:Button ID="btnGenMgrCSV" runat="server" Text="Generate Manager CSV"
    onClientClick="javascript:return fnPopUpCSV(2);" />
    
Tj Kellie
Thanks for your help. Can you give me more detail I am not a professional at this. Would I do this to add the missing pieces? <code> Dim emplTable As DataTable =Nothing Select Case recordID case 1: emplTable = SiteAccess.DownloadEmployee_H() case 2: emplTable = SiteAccess.DownloadManagers() End Select </code>
Nick LaMarca
If you only have 2 methods for getting the data you dont need to get fancy I guess. I just Edited the example to put the code into 2 buttons and changed the js function to pass through the args. I added your select case to the server code too. Hope that helps.
Tj Kellie
In your case here I am not sure lblEmpl.Visible = True can be seen by the main page. So here is what I got if I follow you correctly. on the main page I have buttons (7 different csvs, 7 buttons) called DownloadEmployee for example. I cleck the button in that click event it runs fnPopUp which goes to another page and downloads, but the label is on the main page not the popUp page so it wont see it.
Nick LaMarca