Issues exporting datagridview to excel - c#

I'm trying to do an export of a datagrid to excel. For some reason, known working methods aren't working. The export is done from a user control. My page (default.aspx) uses a master page and the page has a user control that actually has the datagrid I'm trying to export.
Here's my code on the ascx:
Response.ClearContent();
Response.AddHeader("content-disposition", "attachment; filename=MyExcelFile.xls");
Response.ContentType = "application/excel";
StringWriter sw = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(sw);
_gvwResults.RenderControl(htw);
Response.Write(sw.ToString());
Response.End();
On my default.aspx (page the holds the ascx) is this code:
public override void VerifyRenderingInServerForm(Control control)
{
/* Confirms that an HtmlForm control is rendered for the specified ASP.NET
server control at run time. - required to export file */
}
Here's the error I receive:
Sys.Webforms.pagerequestmanagerparsererrorexception. The message received from the server could ot be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, httpmodules or server trace is enabled.
Any ideas? This code should work but it's almost as if the response object is not being cleared. Ideas?

Turns out that the since the combobox was ajaxified, the export was not happening. The event was firing but, as the error message says, it was response.writing onto the existing page, thus throwing the error, which would not allow for a new document (xls in this case) to be rendered. After setting the combobox to do a postback on the page and un-ajaxifying it, the export started working..

Related

Create new page as control and show in a popup window

Essentially, what I want to do is this:
protected void Imgexport_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
//get the download page as an object (requires complex parameter)
GenericExcelDownloader Ged = new GenericExcelDownloader(gvEquipmentRuntime, "Projected Maintenance Report.xls");
//get the response stream from the download page
StringWriter sWriter = new StringWriter();
HtmlTextWriter hTextWriter = new HtmlTextWriter(sWriter);
Ged.RenderControl(hTextWriter);
//????
//Profit?
//WHAT DO?
}
The control I called contains code during page load which essentially ends like so: (there are other modifications made to the grid, which is added to the Div referenced as "Download" below)
Response.ClearContent();
Response.Buffer = true;
Response.AddHeader("content-disposition", "attachment; filename=" + fileName);
Response.Charset = "";
Response.ContentType = "application/excel";
StringWriter sWriter = new StringWriter();
HtmlTextWriter hTextWriter = new HtmlTextWriter(sWriter);
Download.RenderControl(hTextWriter);//this is a Div on the page which contains the visible portion of the page control
Response.Output.Write(sWriter.ToString());
Response.Flush();
Response.End();
The end goal is that on the click of the button, the div on the other page containing a modified version of the grid view passed in as an initial parameter in the click event, is downloaded on the client machine.
Where I'm stuck, is that I dont know how to get the ASPX Page in my code behind which I have as an object, into the front end. I dont even know for sure if my initial attempt is the correct starting place. Because of the complex parameter and its size I dont want to solely rely on a window.open with string parameters and/or a session variable...
UPDATE: WORKAROUND
I found a method which will accomplish my goal, although the original question hasn't actually been answered
By making use of Server.Execute() I was able to directly run the sub-page. It also gives me access to the Page.PreviousPage property, which is an object level reference to the calling page, which contains the complex object I needed. I then can back reference the page to get this object directly on the sub-page. The code looks something like this
protected void Imgexport_Click(object sender, System.Web.UI.ImageClickEventArgs e)
{
Server.Execute("GenericExcelDownloader.aspx?Report=Projected%20Maintenance%20Report%2Exls", true);
}
and on the other side
ReportName = Request.QueryString["Report"];
if (PreviousPage != null && PreviousPage is iReportPage)
ReportGrid = ((iReportPage)PreviousPage).ReportView;
This now allows the page to process directly, and have it's response handled so that it will download the grid the way I need it to.
KNOWN ISSUE:
DataSource in GridView is not stored in any persistent way across Postback so you have to save it somewhere (Viewstate or Session) or you have to request it again from your data-store (Es your db). Gridview Datasource is Null During Postback
I ended up tabling this entire experiment shortly after I got it working because of that. I wanted to avoid stashing all the data in memory, And avoid having to re-generate the grid during the post back. Apparently this is impossible, so I need to accomplish this in a slightly more direct manner.
I'm still quite interested in the answer to the original question though, I can imagine multiple uses for this.

How to export asp grid view inside a user control to excel?

I have a GridView in a WebUserControl in a web page thast uses a master page, and I need to export the grid data to excel and pdf.
I found this code:
Response.AppendHeader("content-disposition", "attachment;filename=ExportedHtml.xls");
Response.Charset = "";
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.ContentType = "application/vnd.ms-excel";
this.EnableViewState = false;
System.IO.StringWriter tw = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter hw = new System.Web.UI.HtmlTextWriter(tw);
((GridView)Hosts.FindControl("hostsGrid")).RenderControl(hw);
Response.Write(tw.ToString());
Response.End();
But I'm getting this error:
Control 'CPH_Body_Hosts_hostsGrid' of type 'GridView' must be placed inside
a form tag with runat=server.
Even though I have a form runat server on the Master page.
Well I found 2 solutions for this problem:
As King.code commented, it was already solved in GridView must be placed inside a form tag with runat=“server” even after the GridView is within a form tag
I also found this sample code that exports in many other formats Export GridView to doc/access/csv/Excel/pdf/xml/html/text/print

GridView export to Excel

I have an asp.net page in which I have a gridview and a button.
On button click event I have wrote the code which exports the gridview to excel which is working very fine.
But when I try to open that exported excel file it shows a dialog box saying:
"The file you are trying to open is in a different format than
specified by the file extension.Verify that the file is not corrupted
and is from a trusted source before opening the file".
Not only that, i sent that excel file as attachment in gmail and tried to open it in mobile, at that time it opens as an html file.What can I do for this because my client will be using mobile to view mails.
I'd recommend creating an actual Excel file instead of a CSV or HTML using an Excel file name extension.
One easy way to accomplish this is using ClosedXML.
To do this, download the ClosedXML.dll and the DocumentFormat.OpenXml.dll from the codeplex site and add them as references in your ASP.NET project. Then, in your button click event, you can simply set up an Excel workbook, create a worksheet from the same DataTable that you are binding to the GridView, and save the workbook file in the HTTP response. Something like this:
var wb = new ClosedXML.Excel.XLWorkbook();
DataTable dt = GetTheDataTable();
dt.TableName = "This will be the worksheet name";
wb.Worksheets.Add(dt);
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;filename=\"FileName.xlsx\"");
using (var ms = new System.IO.MemoryStream()) {
wb.SaveAs(ms);
ms.WriteTo(Response.OutputStream);
ms.Close();
}
Response.End();
I'd go with ClosedXML over other alternatives because the license is less restrictive, the documentation is superb, the developer is helpful and friendly, and the project is currently very active.
In your button click event :
protected void btnExcel_Click(object sender, ImageClickEventArgs e)
{
//export to excel
Response.Clear();
Response.AddHeader("content-disposition", "attachment;filename=FileName.xls");
Response.Charset = "";
// If you want the option to open the Excel file without saving then
// comment out the line below
// Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.ContentType = "application/vnd.xls";
System.IO.StringWriter stringWrite = new System.IO.StringWriter();
System.Web.UI.HtmlTextWriter htmlWrite = new HtmlTextWriter(stringWrite);
//GV is the ID of gridview
GV.RenderControl(htmlWrite);
Response.Write(stringWrite.ToString());
Response.End();
}
and also override this method in your page code behind:
public override void VerifyRenderingInServerForm(Control control)
{
/* Confirms that an HtmlForm control is rendered for the specified ASP.NET
server control at run time. */
}
When I exported to excel, I simply created a comma separated file and gave it an excel file extension. That message went away when I started separating using commas with double quotes.
"one","two","three" rather than one,two,three

Export a GridView in an update panel to Excel and then refresh the grid - not working

I have a gridview in an update panel. I can export it to an excel using HTTP response and it exports the required data and open the file in a pop up which is all working fine.
But, once the data is exported I have to update the grid view indicating that these data were exported. I verified the correct data is set to the data source and databind is called. But the excel export is not triggering the screen to refresh.
If I trigger a refresh by changing a drop down or by something else, I can see the data changed. I tried UpdatePanelID.Update() - still in vain.
So how to trigger a gridview refresh after the excel export?
Thanks in advance.
My code for export:
var excelXml = GetExcelXml(dsInput, filename);
response.Clear();
response.AppendHeader("Content-Type", "application/vnd.ms-excel");
response.AppendHeader("Content-disposition", "attachment; filename=" + filename);
response.Write(excelXml);
response.Flush();
protected void btnExport_Click(object sender, EventArgs e)
{
try
{
if (list.Count() > 0)
{
ds.Tables.Add(dtForExport);
ExcelHelper.ToExcel(ds, filename); //To Excel method is described above.
LoadGridDetails();//Binds the new values
}
}
catch (Exception ex)
{
lblStatus.Text = "Error Exporting to Excel";
}
}//Screen is not refreshed after executing this line.
What you call a «Popup», it seems to me that you are talking about the browser download popup.
So, in this case, it wont work, because you already did an Response.Clear and you can't anymore do an refresh of your grid.
My suggestion is: you can open an real popup it means: window.popup, and this popup will do all the response job, or you can also put some java-script in your button "export" to do two things: do the post-back to export function and wait X milliseconds to call a click of some hidden button just to make a second post-back and do the refresh.
Hope it helps

Export to Excel - ThreadAbortException

I'm having a problem with the conversion to Excel code I'm finding. I am working on a website project in .NET 4.0, and I have created a class for this that does the following (based on
http://mattberseth.com/blog/2007/04/export_gridview_to_excel_1.html):
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.AddHeader("content-disposition",
string.Format("attachment; filename={0}", fileName)); HttpContext.Current.Response.ContentType = "application/ms-excel"; using (StringWriter sw = new StringWriter()) {
using (HtmlTextWriter htw = new HtmlTextWriter(sw)) {
//Create a table to contain the grid
//Add header row
//Add each data row
//Add Footer row
//Render the table into the htmlwriter
// render the htmlwriter into the response
HttpContext.Current.Response.Write(sw.ToString());
HttpContext.Current.Response.End();
}
}
I call this class from a usercontrol that contains a button that is added to a GridView displayed on the page. This works as expected - click the button, you are presented with a download option to either open or save the resulting excel spreadsheet containing the data from the GridView.
However, when I call this from a linkbutton inside a different GridView, I'd like to build a dynamic gridview to contain data and export that. When I do that, I get a ThreadAbortException from the Response.End call in the class.
Question 1: Why do I not get that ThreadAbortException when calling the same code from within a usercontrol? Do usercontrols get their own threads or some other kind of context?
Searching on the error I get when that ThreadAbortException occurs led me to attempt to replace it with ApplicationInstance.CompleteRequest(). When I do that I no longer get the ThreadAbortException, but this breaks the previously working usercontrol - instead of the resulting excel spreadsheet containing the data from the grid, it contains the HTML from the containing page, and at any rate it's easy enough to suppress that error with an empty catch. However, it doesn't fix the direct call with the dynamically generated GridView, that code renders a javascript error: "The message received from the server could not be parsed."
I would love to understand what exactly is going on here, but I'm at the point of needing results regardless of understanding. All the other approaches I've tried (datagrid instead of GridView, etc) run into the same problems, and are essentially the same when it comes down to "taking over"
the current response and using stringwriter and htmlwriter to render the data into a response with excel contentType. And since this demonstrably works in the context of a usercontrol, I am at my wit's end as to why it won't work when called directly...
The problem was actually completely unrelated to the excel export. The “…could not be parsed” error was the key. From these links I got the key, which was that the grid events cause only a partial postback event:
http://forums.asp.net/t/1392827.aspx
http://forums.aspfree.com/net-development-11/gridview-footer-template-button-in-updatepanel-not-posting-back-236087.html
This explains the ThreadAbortException and the “…could not be parsed” error. Adding this to the OnPreRender of the ImageButton was the solution:
protected void addTrigger_PreRender(object sender, EventArgs e)
{
if (sender is ImageButton)
{
ImageButton imgBtn = (ImageButton)sender;
ScriptManager ScriptMgr = (ScriptManager)this.FindControl("ScriptManager1");
ScriptMgr.RegisterPostBackControl(ImgBtn);
}
}
Try instead:
HttpApplication.CompleteRequest()
as per:
http://www.c6software.com/codesolutions/dotnet/threadabortexception.aspx
They discuss the additional html being flished
use this
Response.Clear()
Response.AddHeader("content-disposition", atchment;filename=fm_specification.xls")
Response.Charset = ""
Response.Cache.SetCacheability(HttpCacheability.NoCache)
Response.ContentType = "application/vnd.xls"
Dim stringWrite As System.IO.StringWriter = New System.IO.StringWriter
Dim htmlwrite As System.Web.UI.HtmlTextWriter = New HtmlTextWriter(stringWrite)
GridView1.RenderControl(htmlwrite)
Response.Write(stringWrite.ToString)
Response.End()
instead of gridview1 you can use div
dont forget to add this on your page
Public Overrides Sub VerifyRenderingInServerForm(ByVal control As Control)
End Sub
The event on which the Export to excel code is called, must make a full postback. the issue is because it does only a partial postback.
I had the same error and it got solved when i did a full postback.
Hope this helps someone.

Categories