Archive

Posts Tagged ‘Office’

Usa tipos de contenido MIME para exportar una tabla a Excel


Este es el escenario: tienes un reporte sencillo, y se te ocurrió hacerlo con ASP.NET y alguno de los componentes que tiene para generar, digamos, una tabla HTML. Todo iba bien, el cliente feliz, tu jefe feliz, todos felices. Y de pronto, a alguien se le ocurre: hey, ¿por qué no exportarlo a Excel? Y aquí es donde te da el patatús.

Vamos por partes. Primero creamos nuestro sitio web. El Visual Studio 2010 genera sitios iniciales bonitos, así que usemos ese. Añadimos un control Panel, y ahí dentro vendrá el HTML del reporte. Finalmente, añadamos dos botones: uno para generar el reporte y uno para exportar. El codiguín luciría algo así:

<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <h2>Reporte de productos</h2>
    <p>A continuaci&oacute;n generamos un reporte sencillo y toda la cosa. </p>
    <p>
        <asp:Panel ID="_panel" runat="server">
        </asp:Panel>
        <br /><hr /><br />
        <asp:Button ID="_generateButton" runat="server" Text="Generar" 
            OnClick="OnGenerate" />&nbsp;
        <asp:Button ID="_exportButton" runat="server" Text="Exportar" 
            OnClick="OnExport" />
    </p>
</asp:Content>

Luego, es cuestión de añadir un método, el cual nos genere el reporte. En la vida real sería algo mucho más complicado, pero este es un blog, no la vida real. Entonces hagamos algo más sencillo.

private string GetReport()
{
    Random price = new Random();

    StringBuilder html = new StringBuilder()
        .Append("<table border=\"0\" width=\"100%\">")
        .Append("<tr>")
        .Append("<th>ID</th>")
        .Append("<th>Producto</th>")
        .Append("<th>Precio</th>")
        .Append("<th>Cantidad</th>");
    for (int i = 0; i < 20; i++)
    {
        string color = i % 2 == 0 ? "black" : "white";
        string bg = i % 2 == 0 ? "white" : "gray";
            
        html.AppendFormat("<tr style=\"color:{0}; background-color:{1};\">", 
                    color, bg)
            .AppendFormat("<td>{0}</td>", i)
            .AppendFormat("<td>Producto {0}</td>", i)
            .AppendFormat("<td>{0:C}</td>", price.Next(1, 10000))
            .AppendFormat("<td>{0}</td>", price.Next(1, 1000))
            .Append("</tr>");
    }
    html.Append("</table>");

    return html.ToString();
}

Y ya por último, en el botón Generar, pues generamos el reporte llamando a la función GetReport y metiéndola dentro de un control Literal.

protected void OnGenerate(object sender, EventArgs args)
{
    Literal lit = new Literal();
    lit.Text = GetReport();
    _panel.Controls.Add(lit);
}

Esto nos daría una imagen similar a la siguiente.

image

Bueno, entonces ¿cómo generamos el Excel? Hay varias maneras. La primera, y usualmente la más obvia, sería añadir una referencia a los componentes COM que provee Excel. Una buena medida, sin duda, máxime que el .NET Framework 4, con la introducción de tipos de datos dinámicos ha hecho que trabajar con componentes COM sea mucho más fácil.

Aunque usualmente el problema que hay con esto es un tema de licencias. Verás, para usar esos componentes el servidor web debe tener instalado Microsoft Office (o al menos, Excel). Y alguans empresas no están dispuestas a ello.

Una alternativa es, por supuesto, usar algún otro componente de paga como ASPOSE, o alguno OpenSource como NPOI. Pero a veces restricciones en presupuesto, o políticas, hace que esto no sea posible. En fin. Una solución que reune las tres bes: bueno, bonito y barato, consiste en escribir directamente el HTML de la tabla, y luego cambiar el tipo MIME de la misma.

El asunto es como sigue. MIME significa Multipurpose Internet Mail Extensions. No vamos a entrar en un tema tan largo, pero la idea es que el MIME tiene una propiedad, la cual describe el tipo de contenido que el servidor HTTP está sirviendo: HTML (text/html), JavaScript (text/javascript), etc. Una extensión es la de application/ms-excel, que define un archivo de Excel.

Cambiando el tipo de contenido a application/ms-excel hace que el navegador pase el contenido al programa que lo interpreta, en este caso, a Microsoft Office Excel. Ahora bien, Excel es lo suficientemente inteligente como para interpretar una tabla HTML e incorporar el contenido, aún con colores y toda la cosa. Incluso en algunas ocasiones he visto que incorpore imágenes.

Entonces, el asunto es simple. Para lograrlo hay que hacer varias cosas:

1.- Limpiar el contenido del búfer que el servidor HTTP va a enviar.

2.- Limpiar el encabezado y el contenido previamente establecido.

3.- Establecer el tipo de contenido a application/ms-excel.

4.- Añadir un encabezado que diga que el contenido debe ser tratado como un documento adjunto (y por tanto, descargable).

5.- Escribir el HTML en cuestión y descargar el búfer.

6.- Terminar la respuesta HTTP inmediatamente.

Para hacer estos pasos, usamos el objeto de tipo HttpResponse que toda página ASP.NET expone mediante su propiedad Response.

string html = GetReport();

Response.Clear(); // paso 1
Response.ClearHeaders(); // paso 2
Response.ClearContent(); // paso 2
Response.ContentType = "application/ms-excel"; // paso 3
Response.AppendHeader("Content-Disposition", 
    "attachment; filename=Reporte.xls"); // paso 4
Response.Write(html); // paso 5
Response.Flush(); // paso 5
Response.End(); // paso 6

Y lixto, tenemos un hermoso reporte de Excel, en este caso, el mismo que regresa el método GetReport.

image

Sólo ten en cuenta que esta técnica sirve para reportes sencillos. Para exportar reportes más complicados vale la pena la licencia de Excel o algún otro componente, o incluso pensar en Reporting Services. Ten esta técnica, sin embargo, como tu as bajo la manga, para cuando se necesite algo bueno, bonito y barato.

Categorías:.NET Framework, Apunte, C# Etiquetas: , ,