Exportar de Gridview a Excel con C# Webform

Creo que este tema ya lo han visto en muchos blogs, como exportar de gridview a excel, PERO no tocan el tema de cuando es una consulta de mas de 13 mil registros (y eso que es poco) y que al momento de exportarlos te arroje un excel vació o corrupto, pues a mi me paso, por eso con este humilde post les voy a contar como solucione este problema (gracias a un gran amigo).

¿Que paso?

Bueno, me asignaron un proyecto en la cual necesitaban agregar unas columnas para mostrar unos datos que requería el cliente, si cambios, dije oh! sera algo rápido no me tomara mucho tiempo y lo cual fue cierta… hasta cierto punto… ya que todo funcionaba perfecto en mi maquina… hasta que subir los archivos actualizados al servidor de desarrollo… hicieron una pequeña consulta y BINGO! todo perfecto… hasta que… hicimos la consulta general para mostrar todos los registros, en el preview todo OK pero al momento de exportar el gridview a Excel PUM! no se podía abrir el excel «archivo dañado».

Los problemas

El problema era muy simple, exportar de gridview a excel no debería ser mucho problema… con mi poca experiencia que tengo con C# comencé a hacer pruebas locales cosa que todos me descargaron todos los registros pero al momento de subirlos a desarrollo todo se rompía: archivo dañado, descargaba un archivo con 0 bytes…

¿Como solucione el problema del gridview?

Despues de darle vueltas y vueltas a la manera de resolver este problema, exportar grandes cantidades de registro, pude hacerlo! yes!.

Ahora ¿como lo hice?, he creado 2 funciones y aca lo comparto para que si a alguno le ha pasado lo mismo tenga una solución rápida.

Primera función MExportar

Con la primera funcion llamaremos a nuestra Gridview, en mi caso ya tengo una funcion que hace esto y la convertimos en un DataTable.

C#

privatevoidMExportar()
{
try
{
GridView.AllowPaging=false;
btnBuscar_Click(null,null);//Llamo a mi gridview con toda la data
 
DataTable dt=newDataTable(«Listado de Clientes»);// Asigno un nombre a mi DataTable
 
//Agregamos los encabezados del Gridview al DataTable
 
foreach(TableCell cell inGridView.HeaderRow.Cells)
{
dt.Columns.Add(cell.Text);
}
 
//Agregamos las filas con los registros
 
foreach(GridViewRow row inGridView.Rows)
{
dt.Rows.Add();
for(vari=0;i<row.Cells.Count;i++)
{
varlabel=row.Cells[i].FindControl(«label»+i)asLabel;
if(label!=null)
dt.Rows[dt.Rows.Count1][i]=label.Text;
}
}
 
//Comenzamos a agregar los parametros para generar nuestro Excel
 
varlstrXml=this.XmLizeDt(dt,«»,«»,DateTime.Now.ToString(),«Listado de Clientes»);//Ejecutamos nuestra funcion para generar el excel(el codigo en el siguiente punto)
//dt viene a ser la DataTable, Estructura de nuestro header para el archivo (por ahora no lo vamos a necesitar), Estructura de nuestro footer para el archivo (por ahora no lo vamos a necesitar), Fecha del reporte, Nombre de nuestra hoja
 
varpath=Server.MapPath(«~/Download»)+«\\»;//Asignamos una carpeta temporal en donde se va a generar el archivo
varfilename=DateTime.Now.Ticks.ToString()+«.xls»;//Generamos el nombre del archivo, que en este caso sera la fecha y hora
 
//Explicar para que sirve esta parte seria algo laaaaaaaaaaargo, así que mejor les pongo el link de la documentación https://msdn.microsoft.com/es-es/library/2839d5h5(v=vs.110).aspx
StringBuilder sb=newStringBuilder();
StringWriter sw=newStringWriter(sb);
HtmlTextWriter htw=newHtmlTextWriter(sw);
 
//En esta parte creamos nuestro excel con los datos que nos genero la funcion XmLizeDt
htw.Write(lstrXml);
Response.Clear();
Response.Buffer=true;
System.IO.FileInfo toDownload=newSystem.IO.FileInfo(path+filename);
Page.Response.AddHeader(«Content-Disposition»,«attachment; filename=»+toDownload.Name);
Page.Response.ContentType=«application/octet-stream»;
Page.Response.ContentEncoding=Encoding.UTF8;
Response.Write(sb.ToString());
Response.End();
}
catch(Exception lobjException)
{
//Error
}
}

Esto seria todo para lo que va en la generación del excel.

Segunda función XmLizeDt

Con la siguiente función creamos la estructura de nuestro excel con los datos que generamos en la DataTable, el código es muy simple y eficiente.

C#

publicstringXmLizeDt(DataTable dt,stringbaseStructHeader,stringbaseStructFooter,stringfechaReporte,stringnombreTabla)
{
#region DefaultStruct
intlintColCount=0;
stringlstrXMLHeader=<?xml version=«»1.0«»?>
<?msoapplication progid=«»Excel.Sheet«»?>
<Workbook xmlns=»«urn:schemas-microsoft-com:office:spreadsheet»«
xmlns:o=»«urn:schemas-microsoft-com:office:office»«
xmlns:x=»«urn:schemas-microsoft-com:office:excel»«
xmlns:ss=»«urn:schemas-microsoft-com:office:spreadsheet»«
xmlns:html=»«http://www.w3.org/TR/REC-html40»«>
<DocumentProperties xmlns=»«urn:schemas-microsoft-com:office:office»«>
  <Author>Francisco Cordova</Author>
  <LastAuthor>Francisco Cordova</LastAuthor>
  <Created>2007-03-15T23:04:04Z</Created>
  <Company>Wunderman Phantasia</Company>
  <Version>12.00</Version>
</DocumentProperties>
<ExcelWorkbook xmlns=»«urn:schemas-microsoft-com:office:excel»«>
  <WindowHeight>6795</WindowHeight>
  <WindowWidth>8460</WindowWidth>
  <WindowTopX>120</WindowTopX>
  <WindowTopY>15</WindowTopY>
  <ProtectStructure>False</ProtectStructure>
  <ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID=»»Default»»ss:Name=»»Normal»»>
<Alignment ss:Vertical=»»Bottom»»/>
<Borders/>
<Font ss:FontName=»»Calibri»»x:Family=»»Swiss»»ss:Size=»»11″»ss:Color=»»#000000″»/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
<Style ss:ID=»»s68″»>
<Font ss:FontName=»»Calibri»»x:Family=»»Swiss»»ss:Size=»»11″»ss:Color=»»#FFFFFF»»ss:Bold=»»1″»/>
<Interior ss:Color=»»#CC99FF»»ss:Pattern=»»Solid»»/>
</Style>
<Style ss:ID=»»s65″»>
<Font ss:FontName=»»Calibri»»x:Family=»»Swiss»»ss:Size=»»11″»ss:Color=»»#FFFFFF»»/>
<Interior ss:Color=»»#5B9BD5″»ss:Pattern=»»Solid»»/>
</Style>
</Styles>
<Worksheet ss:Name=»«REPLACENOMBRE»«>
<Table  x:FullColumns=»«1»»   x:FullRows=»«1»«>».Replace(«REPLACENOMBRE»,nombreTabla);
stringlstrXMLFooter=@»  
  </Table>
</Worksheet>
</Workbook>»;
#endregion
 
lintColCount=dt.Rows.Count1;
 
if(baseStructHeader==«»)
{
baseStructHeader=lstrXMLHeader;
}
if(baseStructFooter==«»)
{
baseStructFooter=lstrXMLFooter;
}
StringBuilder output=newStringBuilder();
// Escribir encabezados    
output.Append(baseStructHeader);
//Escribir la cantidad de columnas
foreach(DataColumn dc indt.Columns)
{
output.AppendLine(@»<Column ss:Width=»«200»» />»);
}
 
//Encabezados
output.AppendLine(@»<Row ss:Index=»«2»«>»);
foreach(DataColumn dc indt.Columns)
{
output.AppendLine(@»<Cell ss:StyleID=»«s65»«><Data ss:Type=»«String»«>»+dc.ColumnName+«</Data></Cell>»);
}
output.AppendLine(«</Row>»);
 
 
// Escribir datos    
foreach(DataRow item indt.Rows)
{
intlintCounter=0;
 
output.AppendLine(«<Row>»);
foreach(objectvalue initem.ItemArray)
{
if(dt.Columns[lintCounter].DataType==Type.GetType(«System.String»))
{
 
output.AppendLine(@»<Cell ><Data ss:Type=»«String»«><![CDATA[«+value+«]]></Data></Cell>»);
}
elseif(dt.Columns[lintCounter].DataType==Type.GetType(«System.Decimal»))
{
 
output.AppendLine(@»<Cell ><Data ss:Type=»«Number»«><![CDATA[«+value+«]]></Data></Cell>»);
}
else
{
 
output.AppendLine(@»<Cell ><Data ss:Type=»«String»«><![CDATA[«+value.ToString()+«]]></Data></Cell>»);
}
 
lintCounter++;
}
output.AppendLine(«</Row>»);
}
//Escribir pie
output.Append(baseStructFooter);
// Valor de retorno    
returnoutput.ToString();
}

Espero que les haya sido de utilidad, como lo fue para mi, no se olviden de compartir! 😀

Un gran agradecimiento a mi amigo Danny Siancas por la ayuda 🙂 te debo una caja de alfajores :D!!

Deja un comentario

Tu dirección de correo electrónico no será publicada.

Carrito de compra