Gerando um arquivo Excel em ASP.NET [fechado]

99

Estou prestes a adicionar uma seção a um aplicativo ASP.NET (VB.NET codebehind) que permitirá ao usuário obter dados retornados a eles como um arquivo Excel, que irei gerar com base nos dados do banco de dados. Embora existam várias maneiras de fazer isso, cada uma tem suas próprias desvantagens. Como você retornaria os dados? Estou procurando algo que seja o mais simples e direto possível.

Dan Coates
fonte

Respostas:

131

CSV

Prós:

  • Simples

Contras:

  • Pode não funcionar em outras localidades ou em diferentes configurações do Excel (por exemplo, separador de lista)
  • Não é possível aplicar formatação, fórmulas etc.

HTML

Prós:

  • Ainda muito simples
  • Suporta formatação e fórmulas simples

Contras:

  • Você deve nomear o arquivo como xls e o Excel pode avisá-lo sobre a abertura de um arquivo Excel não nativo
  • Uma planilha por pasta de trabalho

OpenXML (Office 2007 .XLSX)

Prós:

  • Formato nativo do Excel
  • Suporta todos os recursos do Excel
  • Não requer uma cópia de instalação do Excel
  • Pode gerar tabelas dinâmicas
  • Pode ser gerado usando o projeto de código aberto EPPlus

Contras:

  • Compatibilidade limitada fora do Excel 2007 (não deve ser um problema hoje em dia)
  • Complicado, a menos que você esteja usando um componente de terceiros

SpreadSheetML (formato aberto XML)

Prós:

  • Simples em comparação com os formatos nativos do Excel
  • Suporta a maioria dos recursos do Excel: formatação, estilos, fórmulas, várias planilhas por pasta de trabalho
  • O Excel não precisa ser instalado para usá-lo
  • Nenhuma biblioteca de terceiros necessária - apenas escreva seu xml
  • Os documentos podem ser abertos pelo Excel XP / 2003/2007

Contras:

  • Falta de boa documentação
  • Não compatível com versões anteriores do Excel (pré-2000)
  • Somente gravação, uma vez que você o abre e faz alterações no Excel, ele é convertido para o Excel nativo.

XLS (gerado por componente de terceiros)

Prós:

  • Gere arquivo Excel nativo com toda a formatação, fórmulas, etc.

Contras:

  • Custa dinheiro
  • Adicionar dependências

COM Interop

Prós:

  • Usa bibliotecas nativas da Microsoft
  • Leia o suporte para documentos nativos

Contras:

  • Muito devagar
  • Problemas de correspondência de dependência / versão
  • Problemas de simultaneidade / integridade de dados para uso na web durante a leitura
  • Muito devagar
  • Problemas de dimensionamento para uso da web (diferente de simultaneidade): necessidade de criar muitas instâncias de aplicativos pesados ​​do Excel no servidor
  • Requer Windows
  • Eu mencionei que é lento?
Eduardo molteni
fonte
1
A restrição "Somente gravação" mencionada para SpreadsheetML não é totalmente um problema, pois você pode salvar um arquivo Excel como SpreadsheetML se desejar.
Brian
1
SpreadsheetML pode travar o Excel 2003 se você criar arquivos grandes com ele. Não confie nisso: /
Brian
2
Você pode salvar novamente em um arquivo SpreadsheetML no Office 2002 e 2003. Não é necessário Salvar como. SpreadsheetML não pode armazenar macros, gráficos, gráficos e algumas outras vantagens e desvantagens, incluindo os novos recursos do Office 2007 (por exemplo, mais de 3 formatos condicionais). Como o XML é prolixo, compactar SpreadsheetML antes de enviar do servidor (usar SharpZipLib é uma opção) funciona muito bem para reduzir o tempo de download - na verdade, deve ser mencionado que o OpenXML é armazenado em um contêiner ZIP de qualquer maneira. @Brian: Eu uso o SpreadsheetML complexo na faixa de 50-100 MB diariamente sem problemas de travamento.
richardtallent
Se houver a possibilidade de você ter que exportar grandes quantidades de dados, você deve exportar como CSV. Além de SpreadsheetML, é mais difícil fazer uma solução de alto desempenho com qualquer um dos outros formatos. HTML pode ser escrito e lido de forma eficiente, mas precisa de mais especificações de sua parte para ser útil. Tanto o HTML quanto o SpreadsheetML têm outros problemas com relação a arquivos grandes, como Brian mencionou em seu comentário. Então, se você precisa apenas de exportação de dados simples, use CSV.
JohannesH
2
@pomarc: Pode ser simples, mas não está limpo. O usuário deseja um arquivo Excel e você dá a ele um arquivo HTML com uma extensão falsa.
Heinzi,
38

Você pode gerar os dados como células de tabela html, colocar uma extensão .xlsou .xlsxnele e o Excel irá abri-lo como se fosse um documento nativo. Você pode até fazer alguns cálculos limitados de formatação e fórmula dessa maneira, por isso é muito mais poderoso do que CSV. Além disso, a saída de uma tabela html deve ser muito fácil de fazer em uma plataforma da web como ASP.Net;)

Se precisar de várias planilhas ou planilhas nomeadas em sua pasta de trabalho do Excel, você pode fazer algo semelhante por meio de um esquema XML chamado SpreadSheetML. Este não é o novo formato fornecido com o Office 2007, mas algo completamente diferente que funciona desde o Excel 2000. A maneira mais fácil de explicar como funciona é com um exemplo:

<?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
fonte
12
você poderia renomear o arquivo com uma extensão .xml e adicionar isto: <? mso-application progid = "Excel.Sheet"?> logo após o <? xml version = "1.0"?> desta forma o Windows reconhece que o arquivo é um Arquivo do Excel, terá o ícone correto, abrirá o Excel quando você clicar no arquivo e o Excel não reclamará que o formato e o conteúdo do arquivo não coincidem. tchau.
pomarc
1
@pomarc A desvantagem disso é que outros programas que importam arquivos do Excel não o reconhecerão. Mas então, eles provavelmente não analisariam o xml de qualquer maneira.
Joel Coehoorn
1
Usei essa técnica com bastante sucesso. Esta seria a minha recomendação - muito simples e muito eficaz.
NealB
Dois problemas potenciais (YMMV) com dados tabulares HTML mascarados como arquivo XLS: (1) o Microsoft Excel cortará espaços e zeros à esquerda automaticamente; e (2) o Microsoft Excel 2010 avisa o usuário ao abrir um arquivo XLS contendo dados tabulares HTML. A solução para o nº 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (se os espaços / zeros à esquerda forem significativos e precisarem ser mantidos).
iokevins
Apenas para esclarecimento, embora eu tenha mencionado tabelas HTML, o ponto principal dessa resposta é SpreadsheetML, que é mais do que apenas dados tabulares HTML. O Excel o vê como nativo.
Joel Coehoorn
16

Se vier de um 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();
}

De um 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
fonte
1
Apenas o código que eu precisava, obrigado. :)
Kjensen
Scott, o que há com o sinal de libra ("£")? E se eu precisar? Quaisquer outros personagens que são perigosos?
Piotr Owsiak,
PERFEITO. Exatamente o que eu precisava.
Brad Bruce,
o sinal £ é, na verdade, apenas algo de que eu precisava para um de meus clientes. você pode tirá-lo.
SpoiledTechie.com
Dois problemas potenciais (YMMV) com dados tabulares HTML mascarados como arquivo XLS: (1) o Microsoft Excel cortará espaços e zeros à esquerda automaticamente; e (2) o Microsoft Excel 2010 avisa o usuário ao abrir um arquivo XLS contendo dados tabulares HTML. A solução para o nº 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (se os espaços / zeros à esquerda forem significativos e precisarem ser mantidos). Os arquivos de dados CSV também sofrem com o # 1 quando abertos no Microsoft Excel.
iokevins
7

Este é um wrapper gratuito para SpreadML - funciona muito bem.

http://www.carlosag.net/Tools/ExcelXmlWriter/

rp.
fonte
Eu também usei isso - é ótimo.
Paul Suart
Esta biblioteca também permite a leitura de xls?
Alex
5

Com base nas respostas dadas e na consulta com colegas de trabalho, parece que a melhor solução é gerar um arquivo XML ou tabelas HTML e colocá-los como anexo. A única alteração recomendada por meus colegas de trabalho é que os dados (ou seja, as tabelas HTML) podem ser gravados diretamente no objeto Response, eliminando assim a necessidade de gravar um arquivo, o que pode ser problemático devido a problemas de permissões, I / O contenção e garantindo que a limpeza programada ocorra.

Aqui está um trecho do código ... Eu não verifiquei isso ainda, e não forneci todo o código chamado, mas acho que representa bem a ideia.

    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
fonte
2
Dan, você está no caminho certo. E eu definitivamente recomendo SpreadsheetML em vez de HTML - espaço para respirar no futuro, já que o suporte a HTML é frustrantemente limitado. Mas com HTML, SpreadsheetML e OpenXML, os tamanhos dos arquivos podem ser bastante grandes e não serão compactados pelo servidor. OpenXML requer um contêiner ZIP com vários arquivos dentro, e SpreadsheetML e HTML são muito mais rápidos para baixar se você os compactar primeiro e enviar o zip como anexo. Use SharpZipLib e transmita para ele, em vez de diretamente para o Response.
richardtallent
4

como o Excel entende HTML, você pode simplesmente gravar os dados como uma tabela HTML em um arquivo temporário com uma extensão .xls, obter o FileInfo para o arquivo e explodi-lo de volta 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();

se quiser evitar o arquivo temporário, você pode gravar em um fluxo na memória e gravar os bytes de volta em vez de usar WriteFile

se o cabeçalho do comprimento do conteúdo for omitido, você poderá escrever o html diretamente, mas isso pode não funcionar corretamente o tempo todo em todos os navegadores

Steven A. Lowe
fonte
2
Dois problemas potenciais (YMMV) com dados tabulares HTML mascarados como arquivo XLS: (1) o Microsoft Excel cortará espaços e zeros à esquerda automaticamente; e (2) o Microsoft Excel 2010 avisa o usuário ao abrir um arquivo XLS contendo dados tabulares HTML. A solução para o nº 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (se os espaços / zeros à esquerda forem significativos e precisarem ser mantidos).
iokevins
3

Eu pessoalmente prefiro o método XML. Retornarei os dados do banco de dados em um Dataset, salvarei em XMl e, em seguida, crio um arquivo xslt que contém uma regra de transformação que formatará um documento adequado e uma transformação XML simples finalizará o trabalho. A melhor parte disso é que você pode formatar células, fazer formatação condicional, configurar cabeçalhos e rodapés e até mesmo definir intervalos de impressão.

Vendedores Mitchel
fonte
2

Eu fiz isso algumas vezes e a maneira mais fácil era simplesmente retornar um arquivo CSV (Comma Separated Value). O Excel importa perfeitamente e é relativamente rápido de fazer.

Mark Allen
fonte
Um problema potencial (YMMV) com dados CSV: o Microsoft Excel
cortará
2

exportamos dados de um datagrid para o excel o tempo todo. Converter para HTML e, em seguida, gravar em um arquivo 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()

O único problema com esse método era que muitas de nossas grades tinham botões ou links, então você também precisa disso:

'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

Descobri que em algum lugar funciona bem.

WACM161
fonte
2
Dois problemas potenciais (YMMV) com dados tabulares HTML mascarados como arquivo XLS: (1) o Microsoft Excel cortará espaços e zeros à esquerda automaticamente; e (2) o Microsoft Excel 2010 avisa o usuário ao abrir um arquivo XLS contendo dados tabulares HTML. A solução para o nº 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (se os espaços / zeros à esquerda forem significativos e precisarem ser mantidos).
iokevins
2

Aqui está um relatório que extrai de um procedimento armazenado. Os resultados são exportados para o Excel. Ele usa ADO em vez de ADO.NET e a razão pela qual esta linha é

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

Ele faz a maior parte do trabalho e não está disponível em 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
Siddharth Rout
fonte
1

Se você preencher um GridView com dados, você pode usar esta função para obter os dados formatados em HTML, mas indicando ao navegador é um arquivo 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ñó
fonte
Dois problemas potenciais (YMMV) com dados tabulares HTML mascarados como arquivo XLS: (1) o Microsoft Excel cortará espaços e zeros à esquerda automaticamente; e (2) o Microsoft Excel 2010 avisa o usuário ao abrir um arquivo XLS contendo dados tabulares HTML. A solução para o nº 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (se os espaços / zeros à esquerda forem significativos e precisarem ser mantidos).
iokevins
1

Apenas evite a interoperabilidade COM por meio do namespace Microsoft.Office.Interop. É tão lento, não confiável e não escalonável. Não aplicável para masoquistas.

Andrei Rînea
fonte
1

Você pode criar arquivos Excel bem formatados usando esta biblioteca, com bastante facilidade: http://officehelper.codeplex.com/documentation .

O Microsoft Office não precisa ser instalado no servidor da web!

user698116
fonte
0

CSV é a maneira mais fácil. Na maioria das vezes, está vinculado ao Excel. Caso contrário, você deve usar as APIs de automação ou o formato XML. As APIs e XML não são tão difíceis de usar.

Informações sobre como gerar XML para Excel

Ken
fonte
0

Eu opto pelo CSV (conforme descrito acima) ou, com mais frequência atualmente, uso o Infragistics NetAdvantage para gerar o arquivo. (Na grande maioria das vezes em que o Infragistics está em jogo, estamos apenas exportando um UltraWebGrid existente, que é essencialmente uma solução de um LOC, a menos que ajustes extras de formatação sejam necessários. Também poderíamos gerar manualmente um arquivo Excel / BIFF, mas raramente é necessário.)

John Rudy
fonte
0

cara, em .net eu acho que você poderia ter um componente que pudesse fazer isso, mas no asp clássico eu já fiz isso criando uma tabela html e alterando o tipo de mime da página para vnd / msexcel. Eu acho que se você usar um gridview e mudar o tipo MIME talvez funcione, porque o gridview é uma tabela html.


fonte
Dois problemas potenciais (YMMV) com dados tabulares HTML mascarados como arquivo XLS: (1) o Microsoft Excel cortará espaços e zeros à esquerda automaticamente; e (2) o Microsoft Excel 2010 avisa o usuário ao abrir um arquivo XLS contendo dados tabulares HTML. A solução para o nº 1 parece ser creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (se os espaços / zeros à esquerda forem significativos e precisarem ser mantidos).
iokevins
0

A única maneira à prova de balas de evitar os triângulos verdes "Parece que esses números estão armazenados como texto" é usar o formato Open XML. Vale a pena usá-lo, apenas para evitar os inevitáveis ​​triângulos verdes.

Hova
fonte
0

O melhor método que vi para relatórios do Excel é escrever os dados em XML com uma extensão XML e transmiti-los aos clientes com o tipo de conteúdo correto. (aplicativo / xls)

Isso funciona para qualquer relatório que requeira formatação básica e permite que você compare com planilhas existentes usando ferramentas de comparação de texto.

Bravax
fonte
0

Supondo que isso seja para uma intranet, onde você pode definir permissões e comandar o IE, você pode gerar o lado do cliente da pasta de trabalho com JScript / VBScript conduzindo o Excel . Isso fornece a formatação nativa do Excel, sem o incômodo de tentar automatizar o Excel no servidor.

Não tenho certeza se realmente recomendaria mais essa abordagem, exceto em cenários de nicho, mas era bastante comum durante o apogeu clássico do ASP.

Mark Brackett
fonte
0

Claro, você sempre pode ir para componentes de terceiros. Pessoalmente, tive uma boa experiência com Spire.XLS http://www.e-iceblue.com/xls/xlsintro.htm

O componente é muito fácil de usar em seu aplicativo:

        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
fonte
0

Um dos problemas que encontrei ao usar uma das soluções sugeridas acima, que são semelhantes a esta resposta, é que se você enviar o conteúdo como um anexo (o que descobri ser a solução mais limpa para navegadores não-MS) , em seguida, abra-o no Excel 2000-2003, seu tipo é uma "Página da Web do Excel" e não um documento nativo do Excel.

Em seguida, você deve explicar aos usuários como usar "Salvar como tipo" no Excel para convertê-lo em um documento do Excel. Isso é uma dor se os usuários precisam editar este documento e, em seguida, carregá-lo novamente em seu site.

Minha recomendação é usar CSV. É simples e se os usuários o abrirem de dentro do Excel, o Excel pelo menos solicita que salvem em seu formato nativo.

Chad Braun-Duin
fonte
Você precisará ter cuidado com o CSV se seus usuários estiverem espalhados pelo mundo. Aqui na Alemanha, a vírgula é usada como separador decimal e, portanto, o ponto-e-vírgula é usado como separador de valor. Torna difícil criar um arquivo que seja legível em todas as diferentes culturas. Portanto, meu voto seria para um dos formatos XML.
paul
0

Gostaria apenas de criar um arquivo CSV com base nos dados, porque vejo isso como o mais limpo, e o Excel tem um bom suporte para isso. Mas se você precisar de um formato mais flexível, tenho certeza de que existem algumas ferramentas de terceiros para gerar arquivos Excel reais.

Alex Fort
fonte
0

Aqui está uma solução que transmite a tabela de dados como um CSV. Rápido, limpo e fácil, e lida com vírgulas na 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.
fonte
-1

acabei de criar uma função para exportar de um formulário web C # para o Excel, espero que ajude outras pessoas

    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
fonte
-5

Se você tiver que usar o Excel em vez de um arquivo CSV, precisará usar a automação OLE em uma instância do Excel no servidor. A maneira mais fácil de fazer isso é ter um arquivo de modelo e preenchê-lo programaticamente com os dados. Você o salva em outro arquivo.

Dicas:

  • Não faça isso interativamente. Peça ao usuário que inicie o processo e poste uma página com o link para o arquivo. Isso atenua possíveis problemas de desempenho enquanto a planilha é gerada.
  • Use o modelo conforme descrito antes. Isso torna mais fácil modificá-lo.
  • Certifique-se de que o Excel esteja configurado para não abrir caixas de diálogo pop-up. Em um servidor web, isso irá travar toda a instância do Excel.
  • Mantenha a instância do Excel em um servidor separado, de preferência atrás de um firewall, para que não seja exposta como uma possível falha de segurança.
  • Fique de olho no uso de recursos. Gerar um spreadhseet sobre a interface de automação OLE (os PIAs são apenas correções sobre isso) é um processo bastante pesado. Se você precisar dimensionar isso para grandes volumes de dados, pode ser necessário ser um pouco inteligente com sua arquitetura.

Algumas das abordagens de 'usar tipos MIME para enganar o Excel para que ele abra uma tabela HTML' funcionariam se você não se importasse com o formato do arquivo um pouco básico. Essas abordagens também transferem o trabalho pesado da CPU para o cliente. Se você deseja um controle refinado sobre o formato da planilha, provavelmente terá que usar o próprio Excel para gerar o arquivo conforme descrito acima.

ConcernedOfTunbridgeWells
fonte
Má ideia fazer automação a partir de um servidor da web. As alternativas podem parecer hack-ish, mas realmente funcionarão muito melhor.
Joel Coehoorn
Usamos OLE do lado do servidor com o Excel e é uma grande dor de cabeça. Se não fosse pelo risco para nosso produto **, escolheríamos outra solução. ** Melhor o diabo que você sabe ...
DaveE