Génération d'un fichier Excel dans ASP.NET [fermé]


99

Je suis sur le point d'ajouter une section à une application ASP.NET (VB.NET codebehind) qui permettra à un utilisateur de récupérer des données sous forme de fichier Excel, que je générerai en fonction des données de la base de données. Bien qu'il existe plusieurs façons de procéder, chacune a ses propres inconvénients. Comment retourneriez- vous les données? Je recherche quelque chose d'aussi clair et simple que possible.


Réponses:


131

CSV

Avantages:

  • Facile

Les inconvénients:

  • Cela peut ne pas fonctionner dans d'autres paramètres régionaux ou dans différentes configurations Excel (par exemple, séparateur de liste)
  • Impossible d'appliquer la mise en forme, les formules, etc.

HTML

Avantages:

  • Toujours assez simple
  • Prend en charge le formatage et les formules simples

Les inconvénients:

  • Vous devez nommer le fichier xls et Excel peut vous avertir de l'ouverture d'un fichier Excel non natif
  • Une feuille de calcul par classeur

OpenXML (Office 2007 .XLSX)

Avantages:

  • Format Excel natif
  • Prend en charge toutes les fonctionnalités d'Excel
  • Ne nécessite pas de copie d'installation d'Excel
  • Peut générer des tableaux croisés dynamiques
  • Peut être généré à l'aide du projet open source EPPlus

Les inconvénients:

  • Compatibilité limitée en dehors d'Excel 2007 (ne devrait pas être un problème de nos jours)
  • Compliqué sauf si vous utilisez un composant tiers

SpreadSheetML (XML au format ouvert)

Avantages:

  • Simple par rapport aux formats Excel natifs
  • Prend en charge la plupart des fonctionnalités d'Excel: mise en forme, styles, formules, plusieurs feuilles par classeur
  • Excel n'a pas besoin d'être installé pour l'utiliser
  • Aucune bibliothèque tierce nécessaire - écrivez simplement votre xml
  • Les documents peuvent être ouverts par Excel XP / 2003/2007

Les inconvénients:

  • Manque de bonne documentation
  • Non pris en charge dans les anciennes versions d'Excel (avant 2000)
  • En écriture seule, en ce sens qu'une fois que vous l'ouvrez et que vous apportez des modifications à partir d'Excel, il est converti en Excel natif.

XLS (généré par un composant tiers)

Avantages:

  • Générez un fichier Excel natif avec tous les formats, formules, etc.

Les inconvénients:

  • Coût de l'argent
  • Ajouter des dépendances

Interopérabilité COM

Avantages:

  • Utilise les bibliothèques Microsoft natives
  • Lire la prise en charge des documents natifs

Les inconvénients:

  • Très lent
  • Problèmes de correspondance de dépendance / version
  • Problèmes de concurrence / d'intégrité des données pour une utilisation Web lors de la lecture
  • Très lent
  • Problèmes de mise à l'échelle pour l'utilisation Web (différents de la concurrence): nécessité de créer de nombreuses instances d'application Excel lourde sur le serveur
  • Nécessite Windows
  • Ai-je mentionné que c'est lent?

1
La contrainte "écriture seule" mentionnée pour SpreadsheetML n'est pas entièrement un problème, puisque vous pouvez enregistrer un fichier Excel en tant que SpreadsheetML si vous le souhaitez.
Brian

1
SpreadsheetML peut planter Excel 2003 si vous créez de gros fichiers avec. Ne lui faites pas confiance: /
Brian

2
Vous pouvez enregistrer de nouveau dans un fichier SpreadsheetML très bien dans Office 2002 et 2003. Aucun enregistrement sous requis. SpreadsheetML ne peut pas stocker les macros, les graphiques, les graphiques et quelques autres bricoles, y compris les nouvelles fonctionnalités d'Office 2007 (par exemple, plus de 3 formats conditionnels). Étant donné que XML est détaillé, Zipper SpreadsheetML avant l'envoi depuis le serveur (utiliser SharpZipLib est une option) fonctionne très bien pour réduire les temps de téléchargement - en fait, il convient de mentionner qu'OpenXML est de toute façon stocké dans un conteneur ZIP. @Brian: J'utilise quotidiennement SpreadsheetML complexe de 50 à 100 Mo sans problèmes de plantage.
richardtallent

S'il est possible que vous deviez exporter de grandes quantités de données, vous devez les exporter au format CSV. En dehors de SpreadsheetML, il est plus difficile de créer une solution performante avec l'un des autres formats. Le HTML peut être écrit et lu efficacement, mais nécessite des spécifications supplémentaires de votre part pour être utile. HTML et SpreadsheetML ont tous deux d'autres problèmes concernant les gros fichiers comme le mentionne Brian dans son commentaire. Donc, si vous avez juste besoin d'une simple clé d'exportation de données avec CSV.
JohannesH

2
@pomarc: C'est peut-être simple, mais ce n'est pas propre. L'utilisateur veut un fichier Excel et vous lui donnez un fichier HTML avec une fausse extension.
Heinzi

38

Vous pouvez générer les données sous forme de cellules de tableau html, y coller une extension .xlsou .xlsx, et Excel l'ouvrira comme s'il s'agissait d'un document natif. Vous pouvez même effectuer un formatage limité et des calculs de formule de cette façon, c'est donc beaucoup plus puissant que CSV. De plus, la sortie d'une table html devrait être assez facile à faire à partir d'une plate-forme Web comme ASP.Net;)

Si vous avez besoin de plusieurs feuilles de calcul ou feuilles de calcul nommées dans votre classeur Excel, vous pouvez faire quelque chose de similaire via un schéma XML appelé SpreadSheetML. Ce n'est pas le nouveau format fourni avec Office 2007, mais quelque chose de complètement différent qui fonctionne aussi loin que Excel 2000. Le moyen le plus simple d'expliquer comment cela fonctionne est avec un exemple:

<?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> 

12
vous pouvez renommer le fichier avec une extension .xml et ajouter ceci: <? mso-application progid = "Excel.Sheet"?> juste après <? xml version = "1.0"?> de cette façon, les fenêtres reconnaissent que le fichier est un Le fichier Excel, lui donnera la bonne icône, ouvrira Excel lorsque vous cliquez sur le fichier et Excel ne se plaindra pas que le format et le contenu du fichier ne correspondent pas. au revoir.
pomarc

1
@pomarc L'inconvénient est que les autres programmes qui importent des fichiers Excel ne le reconnaîtront pas. Mais alors, ils n'analyseraient probablement pas le XML de toute façon.
Joel Coehoorn

1
J'ai utilisé cette technique avec beaucoup de succès. Ce serait ma recommandation - très simple et très efficace.
NealB

Deux problèmes potentiels (YMMV) avec les données tabulaires HTML masquées sous forme de fichier XLS: (1) Microsoft Excel coupera automatiquement les espaces de début et les zéros; et (2) Microsoft Excel 2010 avertit l'utilisateur lors de l'ouverture d'un fichier XLS contenant des données tabulaires HTML. La solution au n ° 1 semble être creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si les espaces / zéros de début sont significatifs et doivent être conservés).
iokevins

Juste pour clarifier, même si j'ai mentionné les tableaux HTML, le point principal de cette réponse est SpreadsheetML, qui est plus que de simples données tabulaires HTML. Excel le considère comme natif.
Joel Coehoorn

16

Si vous venez d'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();
}

À partir d'un 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);
        }
    }
}

1
Juste le code dont j'avais besoin, merci. :)
Kjensen

Scott, qu'est-ce que c'est que le signe dièse ("£")? Et si j'en ai besoin? Y a-t-il d'autres personnages dangereux?
Piotr Owsiak

PARFAIT. Juste ce dont j'avais besoin.
Brad Bruce

le signe £ est en fait quelque chose dont j'avais besoin pour l'un de mes clients. vous pouvez le retirer.
SpoiledTechie.com

Deux problèmes potentiels (YMMV) avec les données tabulaires HTML masquées sous forme de fichier XLS: (1) Microsoft Excel coupera automatiquement les espaces de début et les zéros; et (2) Microsoft Excel 2010 avertit l'utilisateur lors de l'ouverture d'un fichier XLS contenant des données tabulaires HTML. La solution au n ° 1 semble être creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si les espaces / zéros de début sont significatifs et doivent être conservés). Les fichiers de données CSV souffrent également du n ° 1 lorsqu'ils sont ouverts dans Microsoft Excel.
iokevins


5

Sur la base des réponses données et de la consultation des collègues, il semble que la meilleure solution consiste à générer un fichier XML ou des tableaux HTML et à le pousser vers le bas en tant que pièce jointe. Le seul changement recommandé par mes collègues est que les données (c'est-à-dire les tables HTML) peuvent être écrites directement dans l'objet Response, éliminant ainsi le besoin d'écrire un fichier, ce qui peut être gênant en raison de problèmes d'autorisations, E / S conflit, et s'assurer que la purge programmée a lieu.

Voici un extrait du code ... Je n'ai pas encore vérifié cela, et je n'ai pas fourni tout le code appelé, mais je pense que cela représente bien l'idée.

    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()

2
Dan, tu es sur la bonne voie. Et je recommande définitivement SpreadsheetML plutôt que HTML - une marge de manœuvre pour l'avenir, car le support HTML est frustrant et limité. Mais avec HTML, SpreadsheetML et OpenXML, la taille des fichiers peut être assez volumineuse et ne sera pas gzippée par le serveur. OpenXML nécessite un conteneur ZIP contenant plusieurs fichiers, et SpreadsheetML et HTML sont tous deux beaucoup plus rapides à télécharger si vous les compressez d'abord et envoyez le zip en pièce jointe. Utilisez SharpZipLib et diffusez-y plutôt que directement vers Response.
richardtallent

4

comme Excel comprend le HTML, vous pouvez simplement écrire les données sous forme de tableau HTML dans un fichier temporaire avec une extension .xls, obtenir le FileInfo pour le fichier et le renvoyer en utilisant

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 vous vouliez éviter le fichier temporaire, vous pouvez écrire dans un flux en mémoire et réécrire les octets au lieu d'utiliser WriteFile

si l'en-tête content-length est omis, vous pouvez simplement réécrire le code HTML directement, mais cela peut ne pas fonctionner correctement tout le temps dans tous les navigateurs


2
Deux problèmes potentiels (YMMV) avec les données tabulaires HTML masquées sous forme de fichier XLS: (1) Microsoft Excel coupera automatiquement les espaces de début et les zéros; et (2) Microsoft Excel 2010 avertit l'utilisateur lors de l'ouverture d'un fichier XLS contenant des données tabulaires HTML. La solution au n ° 1 semble être creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si les espaces / zéros de début sont significatifs et doivent être conservés).
iokevins

3

Personnellement, je préfère la méthode XML. Je vais retourner les données de la base de données dans un ensemble de données, les enregistrer dans XMl, puis je crée un fichier xslt qui contient une règle de transformation qui formatera un document approprié, et une simple transformation XML terminera le travail. La meilleure partie de cela, vous pouvez formater les cellules, effectuer une mise en forme conditionnelle, configurer les en-têtes et les pieds de page et même définir des plages d'impression.


2

Je l'ai fait plusieurs fois et à chaque fois, le moyen le plus simple était de simplement renvoyer un fichier CSV (Comma Separated Value). Excel l'importe parfaitement, et c'est relativement rapide à faire.


Un problème potentiel (YMMV) avec les données CSV: Microsoft Excel
coupera

2

nous exportons les données d'une grille de données pour exceller tout le temps. Le convertir en HTML puis l'écrire dans un fichier 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()

Le seul problème avec cette méthode était que beaucoup de nos grilles contenaient des boutons ou des liens, vous en avez donc besoin aussi:

'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

J'ai trouvé que quelque part, ça marche bien.


2
Deux problèmes potentiels (YMMV) avec les données tabulaires HTML masquées sous forme de fichier XLS: (1) Microsoft Excel coupera automatiquement les espaces de début et les zéros; et (2) Microsoft Excel 2010 avertit l'utilisateur lors de l'ouverture d'un fichier XLS contenant des données tabulaires HTML. La solution au n ° 1 semble être creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si les espaces / zéros de début sont significatifs et doivent être conservés).
iokevins


2

Voici un rapport qui provient d'une procédure stockée. Les résultats sont exportés vers Excel. Il utilise ADO au lieu d'ADO.NET et la raison pour laquelle cette ligne

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

Il fait la majeure partie du travail et n'est pas disponible sur 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

1

Si vous remplissez un GridView avec des données, vous pouvez utiliser cette fonction pour obtenir les données au format HTML, mais en indiquant au navigateur qu'il s'agit d'un fichier 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

Deux problèmes potentiels (YMMV) avec les données tabulaires HTML masquées sous forme de fichier XLS: (1) Microsoft Excel coupera automatiquement les espaces de début et les zéros; et (2) Microsoft Excel 2010 avertit l'utilisateur lors de l'ouverture d'un fichier XLS contenant des données tabulaires HTML. La solution au n ° 1 semble être creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si les espaces / zéros de début sont significatifs et doivent être conservés).
iokevins

1

Évitez simplement COM Interop via l'espace de noms Microsoft.Office.Interop. C'est tellement lent et peu fiable et non évolutif. Non applicable pour les masochistes.




0

Je vais soit sur la route CSV (comme décrit ci-dessus), soit plus souvent ces jours-ci, j'utilise Infragistics NetAdvantage pour générer le fichier. (La très grande majorité du temps où Infragistics est en jeu, nous exportons simplement un UltraWebGrid existant, qui est essentiellement une solution à une seule LOC, sauf si des ajustements de formatage supplémentaires sont nécessaires. Nous pourrions également générer manuellement un fichier Excel / BIFF, mais il y en a rarement besoin.)


0

man, dans .net, je suppose que vous pourriez avoir un composant qui pourrait le faire, mais dans asp classique, je l'ai déjà fait en créant une table html et en changeant le tipe mime de la page en vnd / msexcel. Je suppose que si vous utilisez un gridview et changez le type mime, cela devrait peut-être fonctionner, car le gridview est une table html.


Deux problèmes potentiels (YMMV) avec les données tabulaires HTML masquées sous forme de fichier XLS: (1) Microsoft Excel coupera automatiquement les espaces de début et les zéros; et (2) Microsoft Excel 2010 avertit l'utilisateur lors de l'ouverture d'un fichier XLS contenant des données tabulaires HTML. La solution au n ° 1 semble être creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (si les espaces / zéros de début sont significatifs et doivent être conservés).
iokevins

0

Le seul moyen à toute épreuve d'éviter les triangles verts «On dirait que ces nombres sont stockés sous forme de texte» est d'utiliser le format Open XML. Cela vaut la peine de l'utiliser, juste pour éviter les inévitables triangles verts.


0

La meilleure méthode que j'ai vue pour les rapports Excel est d'écrire les données en XML avec une extension XML et de les diffuser aux clients avec le type de contenu approprié. (application / xls)

Cela fonctionne pour tout rapport qui nécessite un formatage de base et vous permet de comparer avec des feuilles de calcul existantes à l'aide d'outils de comparaison de texte.


0

En supposant qu'il s'agit d'un intranet, où vous pouvez définir des autorisations et mandater IE, vous pouvez générer le côté client du classeur avec JScript / VBScript pilotant Excel . Cela vous donne un formatage Excel natif, sans avoir à essayer d'automatiser Excel sur le serveur.

Je ne suis pas sûr de recommander vraiment cette approche, sauf dans des scénarios assez spécialisés, mais c'était assez courant à l'apogée de l'ASP classique.


0

Vous pouvez bien sûr toujours opter pour des composants tiers. Personnellement, j'ai eu une bonne expérience avec Spire.XLS http://www.e-iceblue.com/xls/xlsintro.htm

Le composant est assez facile à utiliser dans votre application:

        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");

0

L'un des problèmes que j'ai rencontrés en utilisant l'une des solutions suggérées ci-dessus qui sont similaires à cette réponse est que si vous transférez le contenu en tant que pièce jointe (ce que j'ai trouvé être la solution la plus propre pour les navigateurs non-ms) , puis ouvrez-le dans Excel 2000-2003, son type est une "Page Web Excel" et non un document Excel natif.

Ensuite, vous devez expliquer aux utilisateurs comment utiliser "Enregistrer en tant que type" à partir d'Excel pour le convertir en un document Excel. C'est pénible si les utilisateurs doivent modifier ce document, puis le télécharger à nouveau sur votre site.

Ma recommandation est d'utiliser CSV. C'est simple et si les utilisateurs l'ouvrent à partir d'Excel, Excel les invite au moins à l'enregistrer dans son format natif.


Vous devrez faire attention avec CSV si vos utilisateurs sont dispersés dans le monde. Ici, en Allemagne, la virgule est utilisée comme séparateur décimal et donc le point-virgule est utilisé comme séparateur de valeur. Rend difficile la création d'un fichier lisible dans toutes les différentes cultures. Mon vote serait donc pour l'un des formats XML.
paul

0

Je créerais simplement un fichier CSV basé sur les données, car je considère que c'est le plus propre et Excel le prend en charge. Mais si vous avez besoin d'un format plus flexible, je suis sûr qu'il existe des outils tiers pour générer de vrais fichiers Excel.


0

Voici une solution qui diffuse la table de données en tant que CSV. Rapide, propre et facile, et il gère les virgules dans l'entrée.

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();
}

-1

vient de créer une fonction pour exporter à partir d'un formulaire Web C # pour exceller en espérant que cela aide les autres

    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();
            }
        }
     }

-5

Si vous devez utiliser Excel au lieu d'un fichier CSV, vous devrez utiliser l'automatisation OLE sur une instance Excel sur le serveur. Le moyen le plus simple de le faire est d'avoir un fichier modèle et de le remplir par programme avec les données. Vous l'enregistrez dans un autre fichier.

Conseils:

  • Ne le faites pas de manière interactive. Demandez à l'utilisateur de lancer le processus, puis de publier une page avec le lien vers le fichier. Cela atténue les problèmes de performances potentiels lors de la génération de la feuille de calcul.
  • Utilisez le modèle comme je l'ai décrit précédemment. Cela facilite sa modification.
  • Assurez-vous qu'Excel est configuré pour ne pas afficher de boîtes de dialogue. Sur un serveur Web, cela bloquera toute l'instance Excel.
  • Conservez l'instance Excel sur un serveur distinct, de préférence derrière un pare-feu, afin qu'elle ne soit pas exposée comme une faille de sécurité potentielle.
  • Gardez un œil sur l'utilisation des ressources. La génération d'un spreadhseet sur l'interface d'automatisation OLE (les PIA ne sont que des cales à ce sujet) est un processus assez lourd. Si vous devez adapter cela à des volumes de données élevés, vous devrez peut-être être un peu intelligent avec votre architecture.

Certaines des approches «utiliser des types mime pour tromper Excel en ouvrant un tableau HTML» fonctionneraient si cela ne vous dérange pas que le format du fichier soit un peu basique. Ces approches génèrent également le gros travail du processeur sur le client. Si vous voulez un contrôle fin sur le format de la feuille de calcul, vous devrez probablement utiliser Excel lui-même pour générer le fichier comme décrit ci-dessus.


Mauvaise idée de faire de l'automatisation à partir d'un serveur Web. Les alternatives peuvent sembler hack-ish, mais elles fonctionneront vraiment beaucoup mieux.
Joel Coehoorn le

Nous utilisons OLE côté serveur avec Excel et c'est une énorme douleur à l'arrière. S'il n'y avait pas de risque pour notre produit **, nous choisirions une autre solution. ** Mieux vaut le diable que vous connaissez ...
DaveE
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.