miércoles, 22 de febrero de 2012

Exportar un DataTable a Excel en ASP.NET

Trabajando en una aplicación web, muchas veces tendremos la necesidad de exportar datos a un fichero de excel para que el usuario los descargue y puedo trabajar con ellos en local.

En este post veremos como exportar un objeto DataTable a excel.

Lo cierto es que el origen de la exportación podría ser cualquiera siempre y cuando durante la generación consigamos generar un fichero .csv que es el que, finalmente, se envía al cliente como un fichero adjunto.

En nuestro ejemplo, llamaremos a un controlador genérico (.ashx) que devolverá un fichero .csv que abrirá sin problemas excel.

El código del controlador es muy sencillo y sólo merece especial atención la llamada al método Utilities.ExportDataTableToExcel.

<%@ WebHandler Language="VB" Class="Export" %>
Imports System
Imports System.Web
Imports System.Data
Imports System.Data.SqlClient
Public Class Export : Implements IHttpHandler
    
    Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
        Dim connectionString As String = "Data Source=ESPIGA\SQL2005; Initial Catalog=MSS; User Id=sa; Password=******"
        Using cnn As New SqlConnection(connectionString)
            Dim selectCommand As String = "SELECT * FROM Customers"
            Dim da As New SqlDataAdapter(selectCommand, cnn)
            Dim ds As New DataSet
            da.Fill(ds)
            Utilities.ExportDataTableToExcel(ds.Tables.Item(0))
        End Using
    End Sub
 
    Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
        Get
            Return False
        End Get
    End Property
End Class


Lo que realmente es interesante es el código del método ExportDataTableToExcel.


    Public Overloads Shared Sub ExportDataTableToExcel(ByVal table As DataTable)
        ExportDataTableToExcel(table, String.Empty, Nothing)
    End Sub
    Public Overloads Shared Sub ExportDataTableToExcel(ByVal table As DataTable, ByVal captions As Dictionary(Of String, String))
        ExportDataTableToExcel(table, String.Empty, captions)
    End Sub
    Public Overloads Shared Sub ExportDataTableToExcel(ByVal table As DataTable, ByVal name As String)
        ExportDataTableToExcel(table, name, Nothing)
    End Sub
    Public Overloads Shared Sub ExportDataTableToExcel(ByVal table As DataTable, ByVal name As String, ByVal captions As Dictionary(Of String, String))
        Dim content As New Text.StringBuilder()
        Dim columnName As String = String.Empty
        For Each column As DataColumn In table.Columns
            If Not captions Is Nothing Then
                If Not captions.TryGetValue(column.ColumnName, columnName) Then
                    columnName = column.ColumnName
                End If
            Else
                columnName = column.ColumnName
            End If
            content.Append(columnName & ";")
        Next
        content.Append(Environment.NewLine)
        Dim value As String
        For Each row As DataRow In table.Rows
            For i As Integer = 0 To table.Columns.Count - 1
                value = String.Empty
                If Not row.IsNull(i) Then
                    value = row(i).ToString().Replace(";", String.Empty)
                End If
                content.Append(value & ";")
            Next
            content.Append(Environment.NewLine)
        Next
        content.Length = content.Length - 1
        Dim context As HttpContext = HttpContext.Current
        With context.Response
            .Clear()
            .ContentType = "text/csv"
            If String.IsNullOrEmpty(name) Then
                name = DateTime.Now.ToString("ddMMyyyyHHmmss")
            End If
            .AppendHeader("Content-Disposition", String.Format("attachment; filename={0}.csv", name))
            .Charset = Encoding.Unicode.WebName
            .ContentEncoding = Encoding.Unicode
            .Write(content.ToString())
            .End()
        End With
    End Sub


Un saludo!

4 comentarios:

  1. Hola! Felicidades, tenés buen contenido en tu blog, me gusta mucho.

    Te tengo una pregunta, sé que no tiene que ver nada con el tema de tu post pero a ver si me ayudas, sale?
    StringCollection es similar a List (Of String) ???
    Sé que una es specialized y la otra es generics.
    Pero digamos que si quiero una lista de cadenas, cuál sería mejor usar? Yo supongo que el StringCollection porque ya viene predefinido que sean cadenas... pero vos qué opinás? o en qué momentos se debe utilizar cada cosa?

    Grcias!

    ResponderEliminar
  2. Hola:
    Gracias por el comentario.
    Respecto a tu duda, yo nunca he utilizado StringCollection, pero buscando un poco he encontrado esto http://stackoverflow.com/questions/7774374/performance-concern-stringcollection-vs-liststring En realidad hay un punto que me hace decantarme por List(Of String) y es que es menos especializada y aprender a usarla será más valioso y reutilizable que aprender a utilizar StringCollection.
    Uff, se que no una respuesta muy definitiva, pero también te diré que no he visto un sólo código con StringCollection, aunque basta que diga estoy hoy para que mañana me tope con él ;-)
    Un saludo.

    ResponderEliminar
    Respuestas
    1. Sergio necesito tu ayuda por favor ... puedes enviarme el projecto a mi correo derebus@hotmail.com ?... estoy tratando de adaptar tu solucion a mi proyecto pero me estanque en un error Sys.WebForms.PageRequestManagerParserErrorException, probe con AsyncPostBackTrigger pero nada ... ayudame por favor

      Eliminar
  3. Hola derebus:
    No sé si será el problema, pero si estás utilizando ASP.NET AJAX la petición al manejador (ashx) no puede ser vía AJAX. Tiene que ser submit convencional.

    ResponderEliminar