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.
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.
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.
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).
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With