Generando un archivo de Excel en ASP.NET [cerrado]

99

Estoy a punto de agregar una sección a una aplicación ASP.NET (código subyacente de VB.NET) que permitirá a un usuario obtener datos devueltos como un archivo de Excel, que generaré en función de los datos de la base de datos. Si bien hay varias formas de hacer esto, cada una tiene sus propios inconvenientes. ¿Cómo que devolver los datos? Estoy buscando algo que sea lo más limpio y sencillo posible.

Dan Coates
fuente

Respuestas:

131

CSV

Pros:

  • Sencillo

Contras:

  • Es posible que no funcione en otras configuraciones regionales o en diferentes configuraciones de Excel (es decir, separador de listas)
  • No se pueden aplicar formatos, fórmulas, etc.

HTML

Pros:

  • Todavía bastante simple
  • Admite formatos y fórmulas simples

Contras:

  • Debe nombrar el archivo como xls y Excel puede advertirle sobre la apertura de un archivo de Excel no nativo
  • Una hoja de trabajo por libro

OpenXML (Office 2007 .XLSX)

Pros:

  • Formato nativo de Excel
  • Admite todas las funciones de Excel
  • No requiere una copia de instalación de Excel
  • Puede generar tablas dinámicas
  • Se puede generar usando el proyecto de código abierto EPPlus

Contras:

  • Compatibilidad limitada fuera de Excel 2007 (no debería ser un problema hoy en día)
  • Complicado a menos que esté utilizando un componente de terceros

SpreadSheetML (formato XML abierto)

Pros:

  • Simple en comparación con los formatos nativos de Excel
  • Admite la mayoría de las funciones de Excel: formato, estilos, fórmulas, varias hojas por libro
  • Excel no necesita estar instalado para usarlo
  • No se necesitan bibliotecas de terceros, solo escriba su xml
  • Los documentos se pueden abrir con Excel XP / 2003/2007

Contras:

  • Falta de buena documentación
  • No es compatible con versiones anteriores de Excel (anteriores a 2000)
  • Solo escritura, ya que una vez que lo abre y hace cambios desde Excel, se convierte a Excel nativo.

XLS (generado por un componente de terceros)

Pros:

  • Genere un archivo de Excel nativo con todos los formatos, fórmulas, etc.

Contras:

  • Cuesta dinero
  • Agregar dependencias

Interoperabilidad COM

Pros:

  • Utiliza bibliotecas nativas de Microsoft
  • Leer soporte para documentos nativos

Contras:

  • Muy lento
  • Problemas de coincidencia de dependencia / versión
  • Problemas de simultaneidad / integridad de datos para uso web al leer
  • Muy lento
  • Problemas de escala para uso web (diferente de la concurrencia): es necesario crear muchas instancias de una aplicación de Excel pesada en el servidor
  • Requiere Windows
  • ¿Mencioné que es lento?
Eduardo Molteni
fuente
1
La restricción de "sólo escritura" mencionada para SpreadsheetML no es un problema del todo, ya que puede guardar un archivo de Excel como SpreadsheetML si lo desea.
Brian
1
SpreadsheetML puede bloquear Excel 2003 si crea archivos grandes con él. No confíes en él: /
Brian
2
Puede guardar de nuevo en un archivo SpreadsheetML sin problemas en Office 2002 y 2003. No se requiere Guardar como. SpreadsheetML no puede almacenar macros, cuadros, gráficos y algunas otras ventajas y desventajas, incluidas las nuevas funciones de Office 2007 (por ejemplo, más de 3 formatos condicionales). Dado que XML es detallado, comprimir SpreadsheetML antes de enviar desde el servidor (usar SharpZipLib es una opción) funciona muy bien para reducir los tiempos de descarga; de hecho, debe mencionarse que OpenXML se almacena en un contenedor ZIP de todos modos. @Brian: uso SpreadsheetML complejo en el rango de 50-100 MB a diario sin problemas de bloqueo.
richardtallent
Si existe la posibilidad de que tenga que exportar grandes cantidades de datos, debe exportar como CSV. Aparte de SpreadsheetML, es más difícil crear una solución eficaz con cualquiera de los otros formatos. HTML se puede escribir y leer de manera eficiente, pero necesita más especificaciones de su parte para que sea útil. Tanto HTML como SpreadsheetML tienen otros problemas relacionados con los archivos grandes, como menciona Brian en su comentario. Entonces, si solo necesita una exportación de datos simple, quédese con CSV.
JohannesH
2
@pomarc: Puede que sea sencillo, pero no está limpio. El usuario quiere un archivo de Excel y le das un archivo HTML con una extensión falsa.
Heinzi
38

Puede generar los datos como celdas de una tabla html, pegarle una extensión .xlso .xlsx, y Excel lo abrirá como si fuera un documento nativo. Incluso puede hacer algunos cálculos de formato y fórmulas limitados de esta manera, por lo que es mucho más poderoso que CSV. Además, generar una tabla html debería ser bastante fácil de hacer desde una plataforma web como ASP.Net;)

Si necesita varias hojas de trabajo u hojas de trabajo con nombre dentro de su libro de Excel, puede hacer algo similar a través de un esquema XML llamado SpreadSheetML. Este no es el nuevo formato que se envió con Office 2007, sino algo completamente diferente que funciona desde Excel 2000. La forma más fácil de explicar cómo funciona es con un ejemplo:

<?xml version="1.0"?>
<?mso-application 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>Your_name_here</Author>
      <LastAuthor>Your_name_here</LastAuthor>
      <Created>20080625</Created>
      <Company>ABC Inc</Company>
      <Version>10.2625</Version>
</DocumentProperties>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
        <WindowHeight>6135</WindowHeight>
        <WindowWidth>8445</WindowWidth>
        <WindowTopX>240</WindowTopX>
        <WindowTopY>120</WindowTopY>
        <ProtectStructure>False</ProtectStructure>
        <ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>

<Styles>
      <Style ss:ID="Default" ss:Name="Normal">
            <Alignment ss:Vertical="Bottom" />
            <Borders />
            <Font />
            <Interior />
            <NumberFormat />
            <Protection />
      </Style>
</Styles>

<Worksheet ss:Name="Sample Sheet 1">
<Table ss:ExpandedColumnCount="2" x:FullColumns="1" x:FullRows="1" ID="Table1">
<Column ss:Width="150" />
<Column ss:Width="200" />
<Row>
      <Cell><Data ss:Type="Number">1</Data></Cell>
      <Cell><Data ss:Type="Number">2</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="Number">3</Data></Cell>
      <Cell><Data ss:Type="Number">4</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="Number">5</Data></Cell>
      <Cell><Data ss:Type="Number">6</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="Number">7</Data></Cell>
      <Cell><Data ss:Type="Number">8</Data></Cell>
</Row>
</Table>
</Worksheet>

<Worksheet ss:Name="Sample Sheet 2">
<Table ss:ExpandedColumnCount="2" x:FullColumns="1" x:FullRows="1" ID="Table2">
<Column ss:Width="150" />
<Column ss:Width="200" />
<Row>
      <Cell><Data ss:Type="String">A</Data></Cell>
      <Cell><Data ss:Type="String">B</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="String">C</Data></Cell>
      <Cell><Data ss:Type="String">D</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="String">E</Data></Cell>
      <Cell><Data ss:Type="String">F</Data></Cell>
</Row>
<Row>
      <Cell><Data ss:Type="String">G</Data></Cell>
      <Cell><Data ss:Type="String">H</Data></Cell>
</Row>
</Table>
</Worksheet>
</Workbook> 
Joel Coehoorn
fuente
12
podría cambiar el nombre del archivo con una extensión .xml y agregar esto: <? mso-application progid = "Excel.Sheet"?> justo después de <? xml version = "1.0"?> de esta manera, Windows reconoce que el archivo es un El archivo de Excel, le dará el icono correcto, se abrirá en Excel cuando haga clic en el archivo y Excel no se quejará de que el formato del archivo y el contenido no coinciden. adiós.
pomarc
1
@pomarc La desventaja es que otros programas que importan archivos de Excel no lo reconocerán. Pero entonces, probablemente no analizarían el xml de todos modos.
Joel Coehoorn
1
He utilizado esta técnica con bastante éxito. Esta sería mi recomendación: muy simple y muy efectiva.
NealB
Dos problemas potenciales (YMMV) con datos tabulares HTML enmascarados como archivo XLS: (1) Microsoft Excel recortará los espacios iniciales y ceros automáticamente; y (2) Microsoft Excel 2010 advierte al usuario cuando abre un archivo XLS que contiene datos tabulares HTML. La solución al n. ° 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si los espacios / ceros iniciales son significativos y deben conservarse).
iokevins
Solo para aclarar, aunque mencioné las tablas HTML, el punto principal de esta respuesta es SpreadsheetML, que es más que solo datos tabulares HTML. Excel lo ve como nativo.
Joel Coehoorn
16

Si viene de un DataTable :

public static void DataTabletoXLS(DataTable DT, string fileName)
{
    HttpContext.Current.Response.Clear();
    HttpContext.Current.Response.Charset = "utf-16";
    HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
    HttpContext.Current.Response.AddHeader("content-disposition", string.Format("attachment; filename={0}.xls", fileName));
    HttpContext.Current.Response.ContentType = "application/ms-excel";

    string tab = "";
    foreach (DataColumn dc in DT.Columns)
    {
        HttpContext.Current.Response.Write(tab + dc.ColumnName.Replace("\n", "").Replace("\t", ""));
        tab = "\t";
    }
    HttpContext.Current.Response.Write("\n");

    int i;
    foreach (DataRow dr in DT.Rows)
    {
        tab = "";
        for (i = 0; i < DT.Columns.Count; i++)
        {
            HttpContext.Current.Response.Write(tab + dr[i].ToString().Replace("\n", "").Replace("\t", ""));
            tab = "\t";
        }
        HttpContext.Current.Response.Write("\n");
    }
    HttpContext.Current.Response.End();
}

Desde Gridview :

public static void GridviewtoXLS(GridView gv, string fileName)
{
    int DirtyBit = 0;
    int PageSize = 0;
    if (gv.AllowPaging == true)
    {
        DirtyBit = 1;
        PageSize = gv.PageSize;
        gv.AllowPaging = false;
        gv.DataBind();
    }

    HttpContext.Current.Response.Clear();
    HttpContext.Current.Response.Charset = "utf-8";
    HttpContext.Current.Response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
    HttpContext.Current.Response.AddHeader(
        "content-disposition", string.Format("attachment; filename={0}.xls", 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
        Table table = new Table();

        //  include the gridline settings
        table.GridLines = gv.GridLines;

        //  add the header row to the table
        if (gv.HeaderRow != null)
        {
            Utilities.Export.PrepareControlForExport(gv.HeaderRow);
            table.Rows.Add(gv.HeaderRow);
        }

        //  add each of the data rows to the table
        foreach (GridViewRow row in gv.Rows)
        {
            Utilities.Export.PrepareControlForExport(row);
            table.Rows.Add(row);
        }

        //  add the footer row to the table
        if (gv.FooterRow != null)
        {
            Utilities.Export.PrepareControlForExport(gv.FooterRow);
            table.Rows.Add(gv.FooterRow);
        }

        //  render the table into the htmlwriter
        table.RenderControl(htw);

        //  render the htmlwriter into the response
        HttpContext.Current.Response.Write(sw.ToString().Replace("£", ""));
        HttpContext.Current.Response.End();
    }

    if (DirtyBit == 1)
    {
        gv.PageSize = PageSize;
        gv.AllowPaging = true;
        gv.DataBind();
    }
}

private static void PrepareControlForExport(Control control)
{
    for (int i = 0; i < control.Controls.Count; i++)
    {
        Control current = control.Controls[i];
        if (current is LinkButton)
        {
            control.Controls.Remove(current);
            control.Controls.AddAt(i, new LiteralControl((current as LinkButton).Text));
        }
        else if (current is ImageButton)
        {
            control.Controls.Remove(current);
            control.Controls.AddAt(i, new LiteralControl((current as ImageButton).AlternateText));
        }
        else if (current is HyperLink)
        {
            control.Controls.Remove(current);
            control.Controls.AddAt(i, new LiteralControl((current as HyperLink).Text));
        }
        else if (current is DropDownList)
        {
            control.Controls.Remove(current);
            control.Controls.AddAt(i, new LiteralControl((current as DropDownList).SelectedItem.Text));
        }
        else if (current is CheckBox)
        {
            control.Controls.Remove(current);
            control.Controls.AddAt(i, new LiteralControl((current as CheckBox).Checked ? "True" : "False"));
        }

        if (current.HasControls())
        {
            Utilities.Export.PrepareControlForExport(current);
        }
    }
}
SpoiledTechie.com
fuente
1
Solo el código que necesitaba, gracias. :)
Kjensen
Scott, ¿qué pasa con el signo de libra ("£")? ¿Y si lo necesito? ¿Algún otro personaje que sea peligroso?
Piotr Owsiak
PERFECTO. Justo lo que necesitaba.
Brad Bruce
el signo £ es en realidad algo que necesitaba para uno de mis clientes. puedes sacarlo.
SpoiledTechie.com
Dos problemas potenciales (YMMV) con datos tabulares HTML enmascarados como archivo XLS: (1) Microsoft Excel recortará los espacios iniciales y ceros automáticamente; y (2) Microsoft Excel 2010 advierte al usuario cuando abre un archivo XLS que contiene datos tabulares HTML. La solución al n. ° 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si los espacios / ceros iniciales son significativos y deben conservarse). Los archivos de datos CSV también sufren el número 1 cuando se abren en Microsoft Excel.
iokevins
5

Según las respuestas dadas y la consulta con los compañeros de trabajo, parece que la mejor solución es generar un archivo XML o tablas HTML y colocarlo como un archivo adjunto. El único cambio recomendado por mis compañeros de trabajo es que los datos (es decir, las tablas HTML) se pueden escribir directamente en el objeto Respuesta, eliminando así la necesidad de escribir un archivo, que puede ser problemático debido a problemas de permisos, E / S contención y garantizar que se produzca la purga programada.

Aquí hay un fragmento del código ... No lo he comprobado todavía y no he proporcionado todo el código llamado, pero creo que representa bien la idea.

    Dim uiTable As HtmlTable = GetUiTable(groupedSumData)

    Response.Clear()

    Response.ContentType = "application/vnd.ms-excel"
    Response.AddHeader("Content-Disposition", String.Format("inline; filename=OSSummery{0:ddmmssf}.xls", DateTime.Now))

    Dim writer As New System.IO.StringWriter()
    Dim htmlWriter As New HtmlTextWriter(writer)
    uiTable.RenderControl(htmlWriter)
    Response.Write(writer.ToString)

    Response.End()
Dan Coates
fuente
2
Dan, estás en el camino correcto. Y definitivamente recomiendo SpreadsheetML en lugar de HTML, un respiro para el futuro, ya que el soporte HTML es frustrantemente limitado. Pero con HTML, SpreadsheetML y OpenXML, los tamaños de archivo pueden ser bastante grandes y el servidor no los comprimirá con gzip. OpenXML requiere un contenedor ZIP con varios archivos adentro, y SpreadsheetML y HTML son mucho más rápidos de descargar si los comprime primero y envía el zip como archivo adjunto. Use SharpZipLib y transmita a él en lugar de directamente a Response.
richardtallent
4

Dado que Excel entiende HTML, puede escribir los datos como una tabla HTML en un archivo temporal con una extensión .xls, obtener FileInfo para el archivo y devolverlo usando

Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" + fi.Name);
Response.AddHeader("Content-Length", fi.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(fi.FullName);
Response.End();

si desea evitar el archivo temporal, puede escribir en un flujo en memoria y volver a escribir los bytes en lugar de usar WriteFile

Si se omite el encabezado de longitud del contenido, puede escribir el html directamente, pero es posible que esto no funcione correctamente todo el tiempo en todos los navegadores.

Steven A. Lowe
fuente
2
Dos problemas potenciales (YMMV) con datos tabulares HTML enmascarados como archivo XLS: (1) Microsoft Excel recortará los espacios iniciales y ceros automáticamente; y (2) Microsoft Excel 2010 advierte al usuario cuando abre un archivo XLS que contiene datos tabulares HTML. La solución al n. ° 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si los espacios / ceros iniciales son significativos y deben conservarse).
iokevins
3

Personalmente prefiero el método XML. Devolveré los datos de la base de datos en un conjunto de datos, los guardaré en XMl, luego creo un archivo xslt que contiene una regla de transformación que formateará un documento adecuado, y una transformación XML simple terminará el trabajo. La mejor parte de esto es que puede formatear celdas, hacer formateo condicional, configurar encabezados y pies de página, e incluso establecer rangos de impresión.

Vendedores de Mitchel
fuente
2

He hecho esto un par de veces y cada vez la forma más fácil era simplemente devolver un archivo CSV (valores separados por comas). Excel lo importa perfectamente y es relativamente rápido de hacer.

Mark Allen
fuente
Un problema potencial (YMMV) con los datos CSV: Microsoft Excel recortará los espacios
iniciales
2

exportamos datos de una cuadrícula de datos para sobresalir todo el tiempo. Convertirlo a HTML y luego escribir en un archivo de Excel

Response.ContentType = "application/vnd.ms-excel"
    Response.Charset = ""
    Response.AddHeader("content-disposition", "fileattachment;filename=YOURFILENAME.xls")
    Me.EnableViewState = False
    Dim sw As System.IO.StringWriter = New System.IO.StringWriter
    Dim hw As HtmlTextWriter = New HtmlTextWriter(sw)
    ClearControls(grid)
    grid.RenderControl(hw)
    Response.Write(sw.ToString())
    Response.End()

El único problema con este método fue que muchas de nuestras cuadrículas tenían botones o enlaces, por lo que también necesita esto:

'needed to export grid to excel to remove link button control and represent as text
Private Sub ClearControls(ByVal control As Control)
    Dim i As Integer
    For i = control.Controls.Count - 1 To 0 Step -1
        ClearControls(control.Controls(i))
    Next i

    If TypeOf control Is System.Web.UI.WebControls.Image Then
        control.Parent.Controls.Remove(control)
    End If

    If (Not TypeOf control Is TableCell) Then
        If Not (control.GetType().GetProperty("SelectedItem") Is Nothing) Then
            Dim literal As New LiteralControl
            control.Parent.Controls.Add(literal)
            Try
                literal.Text = CStr(control.GetType().GetProperty("SelectedItem").GetValue(control, Nothing))
            Catch
            End Try
            control.Parent.Controls.Remove(control)
        Else
            If Not (control.GetType().GetProperty("Text") Is Nothing) Then
                Dim literal As New LiteralControl
                control.Parent.Controls.Add(literal)
                literal.Text = CStr(control.GetType().GetProperty("Text").GetValue(control, Nothing))
                control.Parent.Controls.Remove(control)
            End If
        End If
    End If
    Return
End Sub

Encontré que en alguna parte funciona bien.

WACM161
fuente
2
Dos problemas potenciales (YMMV) con datos tabulares HTML enmascarados como archivo XLS: (1) Microsoft Excel recortará los espacios iniciales y ceros automáticamente; y (2) Microsoft Excel 2010 advierte al usuario cuando abre un archivo XLS que contiene datos tabulares HTML. La solución al n. ° 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si los espacios / ceros iniciales son significativos y deben conservarse).
iokevins
2

Aquí hay un informe que se extrae de un procedimiento almacenado. Los resultados se exportan a Excel. Utiliza ADO en lugar de ADO.NET y la razón por la que esta línea es

oSheet.Cells(2, 1).copyfromrecordset(rst1)

Hace la mayor parte del trabajo y no está disponible en ado.net.

‘Calls stored proc in SQL Server 2000 and puts data in Excel and ‘formats it

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim cnn As ADODB.Connection
        cnn = New ADODB.Connection
        cnn.Open("Provider=SQLOLEDB;data source=xxxxxxx;" & _
          "database=xxxxxxxx;Trusted_Connection=yes;")

        Dim cmd As New ADODB.Command


        cmd.ActiveConnection = cnn


        cmd.CommandText = "[sp_TomTepley]"
        cmd.CommandType = ADODB.CommandTypeEnum.adCmdStoredProc
        cmd.CommandTimeout = 0
        cmd.Parameters.Refresh()


        Dim rst1 As ADODB.Recordset
        rst1 = New ADODB.Recordset
        rst1.Open(cmd)

        Dim oXL As New Excel.Application
        Dim oWB As Excel.Workbook
        Dim oSheet As Excel.Worksheet

        'oXL = CreateObject("excel.application")
        oXL.Visible = True
        oWB = oXL.Workbooks.Add
        oSheet = oWB.ActiveSheet

        Dim Column As Integer
        Column = 1

        Dim fld As ADODB.Field
        For Each fld In rst1.Fields

            oXL.Workbooks(1).Worksheets(1).Cells(1, Column).Value = fld.Name
            oXL.Workbooks(1).Worksheets(1).cells(1, Column).Interior.ColorIndex = 15
            Column = Column + 1

        Next fld

        oXL.Workbooks(1).Worksheets(1).name = "Tom Tepley Report"
        oSheet.Cells(2, 1).copyfromrecordset(rst1)
        oXL.Workbooks(1).Worksheets(1).Cells.EntireColumn.AutoFit()


        oXL.Visible = True
        oXL.UserControl = True

        rst1 = Nothing

        cnn.Close()
        Beep()

    End Sub
Huida de Siddharth
fuente
1

Si llena un GridView con datos, puede usar esta función para obtener los datos en formato HTML, pero indicando al navegador que es un archivo de Excel.

 Public Sub ExportToExcel(ByVal fileName As String, ByVal gv As GridView)

        HttpContext.Current.Response.Clear()
        HttpContext.Current.Response.AddHeader("content-disposition", String.Format("attachment; filename={0}", fileName))
        HttpContext.Current.Response.ContentType = "application/ms-excel"

        Dim sw As StringWriter = New StringWriter
        Dim htw As HtmlTextWriter = New HtmlTextWriter(sw)
        Dim table As Table = New Table

        table.GridLines = gv.GridLines

        If (Not (gv.HeaderRow) Is Nothing) Then
            PrepareControlForExport(gv.HeaderRow)
            table.Rows.Add(gv.HeaderRow)
        End If

        For Each row As GridViewRow In gv.Rows
            PrepareControlForExport(row)
            table.Rows.Add(row)
        Next

        If (Not (gv.FooterRow) Is Nothing) Then
            PrepareControlForExport(gv.FooterRow)
            table.Rows.Add(gv.FooterRow)
        End If

        table.RenderControl(htw)

        HttpContext.Current.Response.Write(sw.ToString)
        HttpContext.Current.Response.End()

    End Sub


    Private Sub PrepareControlForExport(ByVal control As Control)

        Dim i As Integer = 0

        Do While (i < control.Controls.Count)

            Dim current As Control = control.Controls(i)

            If (TypeOf current Is LinkButton) Then
                control.Controls.Remove(current)
                control.Controls.AddAt(i, New LiteralControl(CType(current, LinkButton).Text))

            ElseIf (TypeOf current Is ImageButton) Then
                control.Controls.Remove(current)
                control.Controls.AddAt(i, New LiteralControl(CType(current, ImageButton).AlternateText))

            ElseIf (TypeOf current Is HyperLink) Then
                control.Controls.Remove(current)
                control.Controls.AddAt(i, New LiteralControl(CType(current, HyperLink).Text))

            ElseIf (TypeOf current Is DropDownList) Then
                control.Controls.Remove(current)
                control.Controls.AddAt(i, New LiteralControl(CType(current, DropDownList).SelectedItem.Text))

            ElseIf (TypeOf current Is CheckBox) Then
                control.Controls.Remove(current)
                control.Controls.AddAt(i, New LiteralControl(CType(current, CheckBox).Checked))

            End If

            If current.HasControls Then
                PrepareControlForExport(current)
            End If

            i = i + 1

        Loop

    End Sub
Eduardo Campañó
fuente
Dos problemas potenciales (YMMV) con datos tabulares HTML enmascarados como archivo XLS: (1) Microsoft Excel recortará los espacios iniciales y ceros automáticamente; y (2) Microsoft Excel 2010 advierte al usuario cuando abre un archivo XLS que contiene datos tabulares HTML. La solución al n. ° 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si los espacios / ceros iniciales son significativos y deben conservarse).
iokevins
1

Simplemente evite COM Interop a través del espacio de nombres Microsoft.Office.Interop. Es tan malditamente lento, poco confiable e inescalable. No aplica para masoquistas.

Andrei Rînea
fuente
0

O sigo la ruta CSV (como se describe arriba), o más a menudo en estos días, uso Infragistics NetAdvantage para generar el archivo. (La gran mayoría de las veces en las que Infragistics está en juego, solo estamos exportando un UltraWebGrid existente, que es esencialmente una solución de un LOC a menos que se necesiten ajustes de formato adicionales. También podríamos generar manualmente un archivo Excel / BIFF, pero rara vez es necesario.)

John Rudy
fuente
0

hombre, en .net supongo que podría tener un componente que pudiera hacer eso, pero en el asp clásico ya lo hice creando una tabla html y cambiando el tipo de mime de la página a vnd / msexcel. Supongo que si usa una vista de cuadrícula y cambia el tipo de mime, tal vez debería funcionar, porque la vista de cuadrícula es una tabla html.


fuente
Dos problemas potenciales (YMMV) con datos tabulares HTML enmascarados como archivo XLS: (1) Microsoft Excel recortará los espacios iniciales y ceros automáticamente; y (2) Microsoft Excel 2010 advierte al usuario cuando abre un archivo XLS que contiene datos tabulares HTML. La solución al n. ° 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si los espacios / ceros iniciales son significativos y deben conservarse).
iokevins
0

La única manera infalible de evitar los triángulos verdes "Parece que estos números se almacenan como texto" es utilizar el formato Open XML. Vale la pena usarlo, solo para evitar los inevitables triángulos verdes.

hova
fuente
0

El mejor método que he visto para los informes de Excel es escribir los datos en XML con una extensión XML y transmitirlos a los clientes con el tipo de contenido correcto. (aplicación / xls)

Esto funciona para cualquier informe que requiera un formato básico y le permite comparar con hojas de cálculo existentes mediante el uso de herramientas de comparación de texto.

Bravax
fuente
0

Suponiendo que esto es para una intranet, donde puede establecer permisos y exigir IE, puede generar el lado del cliente del libro de trabajo con JScript / VBScript conduciendo Excel . Esto le brinda formato nativo de Excel, sin la molestia de intentar automatizar Excel en el servidor.

No estoy seguro de si recomendaría realmente este enfoque, excepto en escenarios bastante específicos, pero era bastante común durante el apogeo de ASP clásico.

Mark Brackett
fuente
0

Por supuesto, siempre puede optar por componentes de terceros. Personalmente, he tenido una buena experiencia con Spire.XLS http://www.e-iceblue.com/xls/xlsintro.htm

El componente es bastante fácil de usar dentro de su aplicación:

        Workbook workbook = new Workbook();

        //Load workbook from disk.
        workbook.LoadFromFile(@"Data\EditSheetSample.xls");
        //Initailize worksheet
        Worksheet sheet = workbook.Worksheets[0];

        //Writes string
        sheet.Range["B1"].Text = "Hello,World!";
        //Writes number
        sheet.Range["B2"].NumberValue = 1234.5678;
        //Writes date
        sheet.Range["B3"].DateTimeValue = System.DateTime.Now;
        //Writes formula
        sheet.Range["B4"].Formula = "=1111*11111";

        workbook.SaveToFile("Sample.xls");
Nasir
fuente
0

Uno de los problemas con los que me he encontrado al usar una de las soluciones sugeridas anteriormente, que son similares a esta respuesta, es que si envía el contenido como un archivo adjunto (lo que he encontrado es la solución más limpia para navegadores que no son de MS) , luego ábralo en Excel 2000-2003, su tipo es una "Página Web de Excel" y no un documento nativo de Excel.

Luego, debe explicar a los usuarios cómo usar "Guardar como tipo" desde Excel para convertirlo en un documento de Excel. Esto es una molestia si los usuarios necesitan editar este documento y luego volver a subirlo a su sitio.

Mi recomendación es utilizar CSV. Es simple y si los usuarios lo abren desde Excel, Excel al menos les pide que lo guarden en su formato nativo.

Chad Braun-Duin
fuente
Deberá tener cuidado con CSV si sus usuarios están dispersos por todo el mundo. Aquí en Alemania, la coma se usa como separador decimal y, por lo tanto, el punto y coma se usa como separador de valores. Hace que sea difícil crear un archivo que sea legible en todas las diferentes culturas. Por lo tanto, mi voto sería a favor de uno de los formatos XML.
paul
0

Simplemente crearía un archivo CSV basado en los datos, porque lo veo como el más limpio y Excel tiene un buen soporte para él. Pero si necesita un formato más flexible, estoy seguro de que existen algunas herramientas de terceros para generar archivos de Excel reales.

Alex Fort
fuente
0

Aquí hay una solución que transmite la tabla de datos como un CSV. Rápido, limpio y fácil, y maneja comas en la entrada.

public static void ExportToExcel(DataTable data, HttpResponse response, string fileName)
{
    response.Charset = "utf-8";
    response.ContentEncoding = System.Text.Encoding.GetEncoding("windows-1250");
    response.Cache.SetCacheability(HttpCacheability.NoCache);
    response.ContentType = "text/csv";
    response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);

    for (int i = 0; i < data.Columns.Count; i++)
    {
       response.Write(data.Columns[i].ColumnName);
       response.Write(i == data.Columns.Count - 1 ? "\n" : ",");
    }        
    foreach (DataRow row in data.Rows)
    {
        for (int i = 0; i < data.Columns.Count; i++)
        {
            response.Write(String.Format("\"{0}\"", row[i].ToString()));
            response.Write(i == data.Columns.Count - 1 ? "\n" : ",");
        }
    }

    response.End();
}
Justin R.
fuente
-1

acabo de crear una función para exportar desde un formulario web C # para sobresalir espero que ayude a otros

    public void ExportFileFromSPData(string filename, DataTable dt)
    {
        HttpResponse response = HttpContext.Current.Response;

        //clean up the response.object
        response.Clear();
        response.Buffer = true;
        response.Charset = "";

        // set the response mime type for html so you can see what are you printing 
        //response.ContentType = "text/html";
        //response.AddHeader("Content-Disposition", "attachment;filename=test.html");

        // set the response mime type for excel
        response.ContentType = "application/vnd.ms-excel";
        response.AddHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
        response.ContentEncoding = System.Text.Encoding.UTF8;
        response.BinaryWrite(System.Text.Encoding.UTF8.GetPreamble());

        //style to format numbers to string
        string style = @"<style> .text { mso-number-format:\@; } </style>";
        response.Write(style);

        // create a string writer
        using (StringWriter sw = new StringWriter())
        {
            using (HtmlTextWriter htw = new HtmlTextWriter(sw))
            {
                // instantiate a datagrid
                GridView dg = new GridView();
                dg.DataSource = dt;
                dg.DataBind();

                foreach (GridViewRow datarow in dg.Rows)
                {
                    //format specific cell to be text 
                    //to avoid 1.232323+E29 to get 1232312312312312124124
                    datarow.Cells[0].Attributes.Add("class", "text");
                }

                dg.RenderControl(htw);
                response.Write(sw.ToString());
                response.End();
            }
        }
     }
Steve D Sousa
fuente
-5

Si tiene que utilizar Excel en lugar de un archivo CSV, deberá utilizar la automatización OLE en una instancia de Excel en el servidor. La forma más sencilla de hacer esto es tener un archivo de plantilla y completarlo programáticamente con los datos. Lo guarda en otro archivo.

Consejos:

  • No lo hagas de forma interactiva. Haga que el usuario inicie el proceso y luego publique una página con el enlace al archivo. Esto mitiga posibles problemas de rendimiento mientras se genera la hoja de cálculo.
  • Utilice la plantilla como describí antes. Facilita su modificación.
  • Asegúrese de que Excel esté configurado para no mostrar cuadros de diálogo. En un servidor web, esto colgará toda la instancia de Excel.
  • Mantenga la instancia de Excel en un servidor separado, preferiblemente detrás de un firewall, para que no quede expuesta como un potencial agujero de seguridad.
  • Esté atento al uso de recursos. Generar un diagrama de distribución sobre la interfaz de automatización OLE (los PIA son solo calces sobre esto) es un proceso bastante pesado. Si necesita escalar esto a grandes volúmenes de datos, es posible que deba ser algo inteligente con su arquitectura.

Algunos de los enfoques de 'usar tipos mime para engañar a Excel para que abra una tabla HTML' funcionarían si no le importa que el formato del archivo sea un poco básico. Estos enfoques también transfieren el trabajo pesado de la CPU al cliente. Si desea un control detallado sobre el formato de la hoja de cálculo, probablemente tendrá que utilizar el propio Excel para generar el archivo como se describe anteriormente.

PreocupadoDeTunbridgeWells
fuente
Mala idea hacer automatización desde un servidor web. Las alternativas pueden parecer piratas, pero realmente funcionarán mucho mejor.
Joel Coehoorn
Usamos OLE del lado del servidor con Excel y es un gran dolor en la parte trasera. Si no fuera por el riesgo para nuestro producto **, optaríamos por otra solución. ** Mejor el diablo que conoces ...
DaveE