Generowanie pliku Excela w ASP.NET [zamknięte]


99

Mam zamiar dodać sekcję do aplikacji ASP.NET (za kodem VB.NET), która pozwoli użytkownikowi uzyskać dane zwrócone do niego w postaci pliku Excel, który wygeneruję na podstawie danych z bazy danych. Chociaż można to zrobić na kilka sposobów, każdy ma swoje wady. Jak by pan zwrócić dane? Szukam czegoś tak przejrzystego i prostego, jak to tylko możliwe.


Odpowiedzi:


131

CSV

Plusy:

  • Prosty

Cons:

  • Może nie działać w innych lokalizacjach lub w różnych konfiguracjach programu Excel (np. Separator listy)
  • Nie można zastosować formatowania, formuł itp

HTML

Plusy:

  • Wciąż całkiem proste
  • Obsługuje proste formatowanie i formuły

Cons:

  • Musisz nazwać plik jako xls, a program Excel może ostrzec Cię o otwarciu innego niż natywny plik Excel
  • Jeden arkusz roboczy na skoroszyt

OpenXML (Office 2007 .XLSX)

Plusy:

  • Natywny format Excel
  • Obsługuje wszystkie funkcje programu Excel
  • Nie wymagaj kopii instalacyjnej programu Excel
  • Może generować tabele przestawne
  • Można wygenerować za pomocą projektu open source EPPlus

Cons:

  • Ograniczona kompatybilność poza Excel 2007 (obecnie nie powinno być problemu)
  • Skomplikowane, chyba że używasz komponentu innej firmy

SpreadSheetML (otwarty format XML)

Plusy:

  • Proste w porównaniu z natywnymi formatami Excela
  • Obsługuje większość funkcji programu Excel: formatowanie, style, formuły, wiele arkuszy w skoroszycie
  • Program Excel nie musi być instalowany, aby go używać
  • Żadne biblioteki innych firm nie są potrzebne - po prostu napisz swój XML
  • Dokumenty można otwierać w programie Excel XP / 2003/2007

Cons:

  • Brak dobrej dokumentacji
  • Nieobsługiwane w starszych wersjach programu Excel (starszych niż 2000)
  • Tylko do zapisu, ponieważ po otwarciu i wprowadzeniu zmian w programie Excel jest konwertowany do natywnego programu Excel.

XLS (wygenerowany przez komponent innej firmy)

Plusy:

  • Wygeneruj natywny plik Excel ze wszystkimi formatowaniem, formułami itp.

Cons:

  • Kosztować
  • Dodaj zależności

COM Interop

Plusy:

  • Używa natywnych bibliotek Microsoft
  • Przeczytaj wsparcie dla dokumentów natywnych

Cons:

  • Bardzo wolno
  • Problemy z dopasowaniem zależności / wersji
  • Problemy z współbieżnością / integralnością danych do użytku w Internecie podczas odczytu
  • Bardzo wolno
  • Problemy ze skalowaniem do użytku w Internecie (inne niż współbieżność): potrzeba utworzenia wielu wystąpień ciężkiej aplikacji Excel na serwerze
  • Wymaga systemu Windows
  • Czy wspominałem, że jest wolny?

1
Ograniczenie „tylko do zapisu” wspomniane w przypadku SpreadsheetML nie jest w pełni problemem, ponieważ jeśli chcesz, możesz zapisać plik Excela jako SpreadsheetML.
Brian

1
SpreadsheetML może spowodować awarię programu Excel 2003, jeśli utworzysz za jego pomocą duże pliki. Nie ufaj temu: /
Brian,

2
Możesz zapisać z powrotem do pliku SpreadsheetML bez problemu w Office 2002 i 2003. Nie Zapisz jako wymagane. SpreadsheetML nie może przechowywać makr, wykresów, grafik i kilku innych przypadków, w tym nowych funkcji pakietu Office 2007 (np. Więcej niż 3 formaty warunkowe). Ponieważ XML jest rozwlekły, kompresowanie SpreadsheetML przed wysłaniem z serwera (użycie SharpZipLib jest opcją) działa świetnie, skracając czas pobierania - właściwie należy wspomnieć, że OpenXML jest i tak przechowywany w kontenerze ZIP. @Brian: Codziennie używam złożonego SpreadsheetML w zakresie 50-100 MB bez problemów z awariami.
richardtallent

Jeśli istnieje możliwość, że będziesz musiał wyeksportować duże ilości danych, wyeksportuj je w formacie CSV. Oprócz SpreadsheetML trudniej jest stworzyć wydajne rozwiązanie z jakimkolwiek innym formatem. HTML można efektywnie pisać i czytać, ale wymaga dodatkowej specyfikacji z Twojej strony, aby był użyteczny. Zarówno HTML, jak i SpreadsheetML mają inne problemy dotyczące dużych plików, o czym Brian wspomniał w swoim komentarzu. Więc jeśli potrzebujesz tylko prostego eksportu danych, trzymaj się CSV.
JohannesH

2
@pomarc: To może być proste, ale nie jest czyste. Użytkownik chce pliku Excel, a Ty dajesz mu plik HTML z fałszywym rozszerzeniem.
Heinzi,

38

Możesz wyprowadzić dane jako komórki tabeli html, przykleić do nich rozszerzenie .xlslub .xlsx, a program Excel otworzy je tak, jakby był dokumentem natywnym. W ten sposób możesz nawet wykonać pewne ograniczone formatowanie i obliczenia formuł, więc jest znacznie bardziej wydajne niż CSV. Ponadto utworzenie tabeli html powinno być całkiem łatwe z platformy internetowej, takiej jak ASP.Net;)

Jeśli potrzebujesz wielu arkuszy lub nazwanych arkuszy roboczych w skoroszycie programu Excel, możesz zrobić coś podobnego za pomocą schematu XML o nazwie SpreadSheetML. To nie jest nowy format dostarczany z pakietem Office 2007, ale coś zupełnie innego, co działa już w programie Excel 2000. Najłatwiej wyjaśnić, jak to działa, na przykładzie:

<?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
możesz zmienić nazwę pliku na rozszerzenie .xml i dodać to: <? mso-application progid = "Excel.Sheet"?> zaraz po <? xml version = "1.0"?> w ten sposób system Windows rozpozna, że ​​plik jest Plik Excel, nada mu odpowiednią ikonę, otworzy program Excel po kliknięciu pliku, a program Excel nie będzie narzekał, że format pliku i zawartość nie pasują. PA.
pomarc

1
@pomarc Wadą jest to, że inne programy, które importują pliki Excela, nie rozpoznają tego. Ale wtedy prawdopodobnie i tak nie przeanalizowaliby XML.
Joel Coehoorn

1
Z powodzeniem zastosowałem tę technikę. To byłaby moja rekomendacja - brud prosty i bardzo skuteczny.
NealB

Dwa potencjalne problemy (YMMV) z danymi tabelarycznymi HTML zamaskowanymi jako plik XLS: (1) Microsoft Excel automatycznie obetnie początkowe spacje i zera; oraz (2) Microsoft Excel 2010 ostrzega użytkownika podczas otwierania pliku XLS zawierającego dane tabelaryczne HTML. Rozwiązaniem # 1 wydaje się być creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (jeśli początkowe spacje / zera są znaczące i należy je zachować).
iokevins

Dla wyjaśnienia, chociaż wspomniałem o tabelach HTML, głównym punktem tej odpowiedzi jest SpreadsheetML, który jest czymś więcej niż tylko danymi tabelarycznymi HTML. Excel widzi to jako natywne.
Joel Coehoorn

16

Jeśli pochodzi z 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();
}

Z widoku siatki :

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
Tylko kod, którego potrzebowałem, dzięki. :)
Kjensen

Scott, o co chodzi ze znakiem funta („£”)? A jeśli tego potrzebuję? Jakieś inne postacie, które są niebezpieczne?
Piotr Owsiak

IDEALNY. Dokładnie to, czego potrzebowałem.
Brad Bruce

znak £ jest właściwie czymś, czego potrzebowałem dla jednego z moich klientów. możesz to wyjąć.
SpoiledTechie.com

Dwa potencjalne problemy (YMMV) z danymi tabelarycznymi HTML zamaskowanymi jako plik XLS: (1) Microsoft Excel automatycznie obetnie początkowe spacje i zera; oraz (2) Microsoft Excel 2010 ostrzega użytkownika podczas otwierania pliku XLS zawierającego dane tabelaryczne HTML. Rozwiązaniem # 1 wydaje się być creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (jeśli początkowe spacje / zera są znaczące i należy je zachować). Pliki danych CSV również cierpią z powodu nr 1 po otwarciu w programie Microsoft Excel.
iokevins


5

Na podstawie udzielonych odpowiedzi i konsultacji ze współpracownikami wydaje się, że najlepszym rozwiązaniem jest wygenerowanie pliku XML lub tabel HTML i przesłanie ich jako załącznika. Jedyną zmianą zalecaną przez moich współpracowników jest to, że dane (czyli tabele HTML) można zapisać bezpośrednio do obiektu Response, eliminując w ten sposób konieczność zapisywania pliku, co może być kłopotliwe ze względu na problemy z uprawnieniami, I / O rywalizacja i zapewnienie zaplanowanego czyszczenia.

Oto fragment kodu ... Jeszcze tego nie sprawdziłem i nie dostarczyłem całego wywoływanego kodu, ale myślę, że dobrze oddaje ideę.

    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, jesteś na dobrej drodze. Zdecydowanie polecam SpreadsheetML zamiast HTML - oddech na przyszłość, ponieważ obsługa HTML jest frustrująco ograniczona. Jednak w przypadku HTML, SpreadsheetML i OpenXML rozmiary plików mogą być dość duże i serwer nie może ich zgzipować. OpenXML wymaga kontenera ZIP z wieloma plikami w środku, a pobieranie SpreadsheetML i HTML jest znacznie szybsze, jeśli najpierw je spakujesz i wyślesz jako załącznik. Użyj SharpZipLib i przesyłaj strumieniowo do niego, a nie bezpośrednio do Response.
richardtallent

4

ponieważ Excel rozumie HTML, możesz po prostu zapisać dane jako tabelę HTML do pliku tymczasowego z rozszerzeniem .xls, pobrać FileInfo dla pliku i odrzucić go za pomocą

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

jeśli chcesz uniknąć pliku tymczasowego, możesz zapisać do strumienia w pamięci i zapisać bajty z powrotem zamiast używać WriteFile

jeśli pominięto nagłówek content-length, możesz po prostu napisać bezpośrednio kod HTML, ale może to nie działać poprawnie przez cały czas we wszystkich przeglądarkach


2
Dwa potencjalne problemy (YMMV) z danymi tabelarycznymi HTML zamaskowanymi jako plik XLS: (1) Microsoft Excel automatycznie obetnie początkowe spacje i zera; oraz (2) Microsoft Excel 2010 ostrzega użytkownika podczas otwierania pliku XLS zawierającego dane tabelaryczne HTML. Rozwiązaniem # 1 wydaje się być creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (jeśli początkowe spacje / zera są znaczące i należy je zachować).
iokevins

3

Osobiście wolę metodę XML. Zwrócę dane z bazy danych w zestawie danych, zapiszę je w XMl, a następnie utworzę plik xslt, który zawiera regułę transformacji, która sformatuje odpowiedni dokument, a prosta transformacja XML zakończy pracę. Najlepszą częścią tego jest formatowanie komórek, formatowanie warunkowe, konfigurowanie nagłówków i stopek, a nawet ustawianie zakresów drukowania.


2

Zrobiłem to kilka razy i za każdym razem najłatwiej było po prostu zwrócić plik CSV (Comma Separated Value). Excel importuje go doskonale i jest to stosunkowo szybkie.


Jeden potencjalny problem (YMMV) z danymi CSV: Microsoft Excel automatycznie
obetnie początkowe

2

eksportujemy dane z datagridu, aby cały czas doskonalić się. Konwertowanie go do formatu HTML, a następnie zapisywanie w pliku programu 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()

Jedynym problemem związanym z tą metodą było to, że wiele naszych siatek miało w sobie przyciski lub linki, więc również tego potrzebujesz:

'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

Znalazłem to gdzieś, działa dobrze.


2
Dwa potencjalne problemy (YMMV) z danymi tabelarycznymi HTML zamaskowanymi jako plik XLS: (1) Microsoft Excel automatycznie obetnie początkowe spacje i zera; oraz (2) Microsoft Excel 2010 ostrzega użytkownika podczas otwierania pliku XLS zawierającego dane tabelaryczne HTML. Rozwiązaniem # 1 wydaje się być creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (jeśli początkowe spacje / zera są znaczące i należy je zachować).
iokevins


2

Oto raport, który pobiera z procedury składowanej. Wyniki są eksportowane do programu Excel. Używa ADO zamiast ADO.NET i powód, dla którego jest to linia

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

Wykonuje większość pracy i nie jest dostępny w 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

Jeśli wypełnisz widok GridView danymi, możesz użyć tej funkcji, aby uzyskać dane w formacie HTML, ale wskazując, że przeglądarka jest plikiem programu 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

Dwa potencjalne problemy (YMMV) z danymi tabelarycznymi HTML zamaskowanymi jako plik XLS: (1) Microsoft Excel automatycznie obetnie początkowe spacje i zera; oraz (2) Microsoft Excel 2010 ostrzega użytkownika podczas otwierania pliku XLS zawierającego dane tabelaryczne HTML. Rozwiązaniem # 1 wydaje się być creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (jeśli początkowe spacje / zera są znaczące i należy je zachować).
iokevins

1

Po prostu unikaj COM Interop za pośrednictwem przestrzeni nazw Microsoft.Office.Interop. Jest tak cholernie powolny, zawodny i nieskalowalny. Nie dotyczy masochistów.




0

Albo wybieram trasę CSV (jak opisano powyżej), albo częściej używam Infragistics NetAdvantage do generowania pliku. (W bardzo zdecydowanej większości przypadków, gdy w grze działa Infragistics, po prostu eksportujemy istniejący UltraWebGrid, który jest zasadniczo rozwiązaniem typu one-LOC, chyba że potrzebne są dodatkowe poprawki formatowania. Moglibyśmy również ręcznie wygenerować plik Excel / BIFF, ale rzadko jest taka potrzeba).


0

stary, w .net myślę, że mógłbyś mieć komponent, który by to potrafił, ale w klasycznym asp, zrobiłem to już tworząc tabelę html i zmieniając tipe strony na vnd / msexcel. Myślę, że jeśli używasz widoku siatki i zmieniasz typ MIME, może to powinno działać, ponieważ widok siatki jest tabelą html.


Dwa potencjalne problemy (YMMV) z danymi tabelarycznymi HTML zamaskowanymi jako plik XLS: (1) Microsoft Excel automatycznie obetnie początkowe spacje i zera; oraz (2) Microsoft Excel 2010 ostrzega użytkownika podczas otwierania pliku XLS zawierającego dane tabelaryczne HTML. Rozwiązaniem # 1 wydaje się być creativyst.com/Doc/Articles/CSV/CSV01.htm#CSVAndExcel (jeśli początkowe spacje / zera są znaczące i należy je zachować).
iokevins

0

Jedynym niezawodnym sposobem uniknięcia zielonych trójkątów „Wygląda na to, że te liczby są przechowywane jako tekst” jest użycie formatu Open XML. Warto z niego skorzystać, byle tylko uniknąć nieuniknionych zielonych trójkątów.


0

Najlepszą metodą, jaką widziałem w przypadku raportów programu Excel, jest zapisywanie danych w formacie XML z rozszerzeniem XML i przesyłanie ich strumieniowo do klientów z odpowiednim typem zawartości. (aplikacja / xls)

Działa to w przypadku każdego raportu wymagającego podstawowego formatowania i umożliwia porównanie z istniejącymi arkuszami kalkulacyjnymi przy użyciu narzędzi do porównywania tekstu.


0

Zakładając, że dotyczy to intranetu, w którym można ustawić uprawnienia i nadać uprawnienia IE, można wygenerować stronę klienta skoroszytu za pomocą języka JScript / VBScript sterującego programem Excel . Zapewnia to natywne formatowanie programu Excel, bez kłopotów związanych z automatyzacją programu Excel na serwerze.

Nie jestem pewien, czy naprawdę poleciłbym to podejście, z wyjątkiem dość niszowych scenariuszy, ale było to dość powszechne w czasach świetności klasycznej ASP.


0

Oczywiście zawsze możesz wybrać komponenty innej firmy. Osobiście mam dobre doświadczenia ze Spire.XLS http://www.e-iceblue.com/xls/xlsintro.htm

Komponent jest dość łatwy w użyciu w twojej aplikacji:

        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

Jeden z problemów, na które natknąłem się, używając jednego z sugerowanych powyżej rozwiązań, które są podobne do tej odpowiedzi jest to, że jeśli wypchniesz zawartość jako załącznik (to, co uważam za najczystsze rozwiązanie dla przeglądarek innych niż ms) , a następnie otwórz go w programie Excel 2000-2003, jego typ to „Strona internetowa programu Excel”, a nie natywny dokument programu Excel.

Następnie musisz wyjaśnić użytkownikom, jak używać funkcji „Zapisz jako typ” w programie Excel, aby przekonwertować ją na dokument Excel. Jest to uciążliwe, jeśli użytkownicy muszą edytować ten dokument, a następnie ponownie przesłać go do Twojej witryny.

Moją rekomendacją jest użycie CSV. Jest to proste i jeśli użytkownicy otwierają go z poziomu programu Excel, program Excel przynajmniej monituje ich o zapisanie go w jego natywnym formacie.


Musisz uważać na CSV, jeśli Twoi użytkownicy są rozproszeni po całym świecie. Tutaj w Niemczech przecinek jest używany jako separator dziesiętny, dlatego średnik jest używany jako separator wartości. Utrudnia utworzenie jednego pliku, który jest czytelny we wszystkich kulturach. Dlatego mój głos byłby za jednym z formatów XML.
paul

0

Po prostu utworzyłbym plik CSV na podstawie danych, ponieważ uważam go za najczystszy, a Excel ma do tego dobrą obsługę. Ale jeśli potrzebujesz bardziej elastycznego formatu, jestem pewien, że istnieją narzędzia innych firm do generowania prawdziwych plików Excela.


0

Oto rozwiązanie, które przesyła dane jako plik CSV. Szybki, czysty i łatwy oraz obsługuje przecinki w danych wejściowych.

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

właśnie stworzyłem funkcję eksportu z formularza internetowego C #, aby mieć nadzieję, że pomoże to innym

    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

Jeśli musisz użyć programu Excel zamiast pliku CSV, będziesz musiał użyć automatyzacji OLE na instancji programu Excel na serwerze. Najłatwiejszym sposobem jest posiadanie pliku szablonu i programowe wypełnienie go danymi. Zapisujesz go w innym pliku.

Porady:

  • Nie rób tego interaktywnie. Poproś użytkownika o rozpoczęcie procesu, a następnie opublikowanie strony z łączem do pliku. Zmniejsza to potencjalne problemy z wydajnością podczas generowania arkusza kalkulacyjnego.
  • Użyj szablonu, jak opisałem wcześniej. Ułatwia to modyfikowanie.
  • Upewnij się, że program Excel nie ma wyskakujących okien dialogowych. Na serwerze WWW spowoduje to zawieszenie całej instancji programu Excel.
  • Zachowaj wystąpienie programu Excel na oddzielnym serwerze, najlepiej za zaporą, aby nie było narażone jako potencjalna luka w zabezpieczeniach.
  • Miej oko na wykorzystanie zasobów. Generowanie arkusza kalkulacyjnego przez interfejs automatyzacji OLE (PIA to tylko podkładki) to dość ciężki proces. Jeśli potrzebujesz skalować to do dużych ilości danych, być może będziesz musiał sprytnie posługiwać się architekturą.

Niektóre metody „używaj typów MIME, aby oszukać program Excel przy otwieraniu tabeli HTML” będą działać, jeśli nie masz nic przeciwko temu, że format pliku jest nieco prosty. Podejścia te powodują również przeniesienie ciężkiej pracy procesora na klienta. Jeśli chcesz mieć dokładną kontrolę nad formatem arkusza kalkulacyjnego, prawdopodobnie będziesz musiał użyć samego programu Excel do wygenerowania pliku, jak opisano powyżej.


Zły pomysł na automatyzację z serwera WWW. Alternatywy mogą wydawać się hakerskie, ale naprawdę będą działać znacznie lepiej.
Joel Coehoorn

Używamy OLE po stronie serwera z Excelem i jest to ogromny problem. Gdyby nie ryzyko związane z naszym produktem **, wybralibyśmy inne rozwiązanie. ** Lepiej diabeł, którego znasz ...
DaveE
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.