Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why won't Response.Write() export a CSV file to the browser?

Tags:

c#

csv

asp.net

I'm trying to export the contents of a DataTable to the user's browser as an Excel .csv file. When I click the "Export" button and step through my code in the debugger, everything looks like it's happening, but no file actually gets sent to the browser. The thing is, I'm using this EXACT SAME CODE in another project and it works there.

EDIT: Here's my ASPX markup for the entire UpdatePanel containing the button:

<asp:UpdatePanel ID="updNoUsage" runat="server">
  <ContentTemplate>
    <asp:Button ID="btnNoUsageLookup" runat="server" Text="Get No Usage Lines Report"
      OnClick="btnNoUsageLookup_Click" /><br /><br />
    <asp:Label ID="lblNoUsageMessage" runat="server" Font-Bold="True" ForeColor="Blue"
      Text="Message" Visible="False"></asp:Label><br /><br />
    <asp:Panel ID="pnlNoUsageReport" runat="server" Visible="False" BorderStyle="None">
      <asp:GridView ID="gvNoUsage" runat="server" AllowPaging="True" AllowSorting="True"
        AutoGenerateColumns="False" BorderColor="#666666" BorderStyle="Solid"
        BorderWidth="1px" PageSize="25" OnPageIndexChanging="gv_PageIndexChanging"
        OnSorting="gv_Sorting" OnRowCreated="gvNoUsage_RowCreated">
          <HeaderStyle BackColor="Transparent" />
          <RowStyle BackColor="#e5e5e5" />
          <AlternatingRowStyle BackColor="White" />
          <Columns>
            <asp:BoundField DataField="CostCenter" HeaderText="Cost Center" SortExpression="CostCenter" />
            <asp:BoundField DataField="WirelessNumber" HeaderText="Wireless Number" SortExpression="WirelessNumber" />
            <asp:BoundField DataField="ESN" HeaderText="ESN" SortExpression="ESN" />
            <asp:BoundField DataField="UserName" HeaderText="User Name" SortExpression="UserName" />
            <asp:BoundField DataField="Model" HeaderText="Handset Model" SortExpression="Model" />
          </Columns>
        </asp:GridView>
        <ajaxToolkit:AnimationExtender ID="aeNoUsage" runat="server" 
          TargetControlID="gvNoUsage">
          <Animations>
            <OnLoad>
              <Sequence>
        <FadeIn AnimationTarget="gvNoUsage" Duration=".25" />
          </Sequence>
            </OnLoad>
          </Animations>
        </ajaxToolkit:AnimationExtender>
        <br /><br />
        <asp:Button ID="btnNoUsageExport" runat="server" CausesValidation="false" 
          Text="Export to Excel" OnClick="btnExport_Click" />
      </asp:Panel>
    </ContentTemplate>
    <Triggers>
      <asp:AsyncPostBackTrigger ControlID="btnNoUsageLookup" EventName="Click" />
      <asp:AsyncPostBackTrigger ControlID="btnNoUsageExport" EventName="Click" />
    </Triggers>
  </asp:UpdatePanel>

Here's the "btnExport_Click" C# function in the code behind:

protected void btnExport_Click(object sender, EventArgs e)
{
  //Get dataset and output filename
  DataTable dt = dtNoUsage;
  string exportFile = "No Usage Report.csv";

  //Now convert DataSet to a CSV file
  //  Clear the response so there is nothing coming back.
  Response.Clear();
  Response.ClearHeaders();

  //  Add an HTTP header for the content type to tell the browser that this is a file that is being passed back.
  Response.AddHeader("Content-Disposition", string.Format("attachment; filename={0}", exportFile));

  //  Tell the browser the correct file type (should cause the file to open with Microsoft Excel)
  Response.ContentType = "application/vnd.ms-excel";

  //  Get CSV file from DataTable
  string csvData = HelperFunctions.CreateCSVFile(dt);

  //  Write the response to the HTTP stream back to the client browser
  Response.Write(csvData);

  //  End the stream write and commit it
  Response.End();
}

Here's the HelperFunctions.CreateCSVFile() method:

public static string CreateCSVFile(DataTable dt)
{
  //  Build the file line by line from the DataSet
  StringBuilder sbFile = new StringBuilder();

  //  Add the header row
  for (int i = 0; i < dt.Columns.Count; i++)
  {
    sbFile.AppendFormat("{0}", EscapeCSVField(dt.Columns[i].ColumnName));
    if (i < dt.Columns.Count - 1)
    {
      sbFile.Append(",");
    }
  }
  //  Add a newline
  sbFile.AppendLine(String.Empty);
  //  Add the data rows
  for (int i = 1; i < dt.Rows.Count; i++)
  {
    for (int j = 0; j < dt.Columns.Count; j++)
    {
      sbFile.AppendFormat("{0}", EscapeCSVField(dt.Rows[i][j].ToString().Trim()));
      if (j < dt.Columns.Count - 1)
      {
        sbFile.Append(",");
      }
    }
    //  Add a newline
    sbFile.AppendLine(String.Empty);
  }
  return sbFile.ToString();
}

Like I said, this same code is working perfectly in another project. Any ideas what might be happening?

EDIT: I watched the response in Fiddler, and as far as I can tell, the correct response is coming back - the browsers (Chrome, IE, Firefox) are just not responding to the file that is sent. Here's what the response looks like:

HTTP/1.1 200 OK
Cache-Control: public
Content-Type: application/vnd.ms-excel; charset=utf-8
Server: Microsoft-IIS/8.0
Content-Disposition: attachment; filename=Upgrade Eligibility Report.csv
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?YzpcdXNlcnNcdGltb3RoeWJcZG9jdW1lbnRzXHZpc3VhbCBzdHVkaW8gMjAxMlxQcm9qZWN0c1xXaXJlbGVzc0JpbGxpbmdWMlxXaXJlbGVzc0JpbGxpbmdWMlxVc2VyXFdpcmVsZXNzQmlsbGluZy5hc3B4?=
X-Powered-By: ASP.NET
Date: Tue, 29 Oct 2013 15:19:43 GMT
Content-Length: 16310

Then there's a blank line and the file contents are dumped. The contents also look correct. I'm baffled.

like image 214
timbck2 Avatar asked Oct 28 '13 21:10

timbck2


People also ask

How do I export data from CSV to website?

There is no simple solution to export a website to a CSV file. The only way to achieve this is by using a web scraping setup and some automation. A web crawling setup will have to be programmed to visit the source websites, fetch the required data from the sites and save it to a dump file.

How do I save a CSV file in Javascript?

Click on the given Export to HTML table to CSV File button to download the data to CSV file format. The file will download by the name of person. csv. You can open this file in MS-Excel to see the data contained inside it.

How do I export a csv file?

Go to File > Save As. Click Browse. In the Save As dialog box, under Save as type box, choose the text file format for the worksheet; for example, click Text (Tab delimited) or CSV (Comma delimited).


2 Answers

The UpdatePanel is probably the problem here. You're writing the file directly to the response, but the UpdatePanel is using Microsoft's funky AJAX voodoo, which expects its result to come back as its own special breed of HTML and data. I'd bet their javascript is throwing an error.

If you remove the button from the update panel, you should be ok.

like image 156
Joe Enos Avatar answered Sep 27 '22 02:09

Joe Enos


As @JoeEnos explained, your UpdatePanel is the culprit. Make the btnNoUsageExport do a postback in your UpdatePanel's Triggers section:

<asp:PostBackTrigger ControlID="btnNoUsageExport" />

This way the response will be sent to the browser instad of interpreted by MS's AJAX-script.

like image 36
CodeCaster Avatar answered Sep 25 '22 02:09

CodeCaster