Экспорт таблицы в Excel из ASP.NET: Content-Disposition и GridView

РазделASP.NETУровеньНовичок Чтение8 минОпубликовано ТегиASP.NETExcelGridViewVB.NET

Пользователи рано или поздно просят кнопку «Выгрузить в Excel». Разбираем самый простой способ отдать таблицу из ASP.NET, не ставя на сервер ни Office, ни сторонних библиотек.

Главное. Пара HTTP-заголовков и отрисованный GridView дают рабочую кнопку «Выгрузить в Excel» без сторонних компонентов, но результат остаётся HTML-файлом с ограничениями формата.

Идея: браузеру говорят, что это файл

Браузер решает, показать ответ сервера или предложить его сохранить, по двум HTTP-заголовкам. Content-Type сообщает, что за данные пришли, а Content-Disposition со значением attachment просит не открывать содержимое в окне, а скачать его под указанным именем. Если указать тип application/vnd.ms-excel и имя с расширением .xls, браузер откроет загрузку, а Windows предложит открыть файл в Excel.

Сам Excel умеет читать не только свой двоичный формат, но и HTML-таблицы. Именно на этом построен приём: страница выводит обычную разметку table, а Excel при открытии превращает её в лист с ячейками. Никаких библиотек и установленного Office на сервере не требуется, поэтому способ годится даже для дешёвого хостинга.

Заголовки ответа

Перед выводом данных ответ нужно очистить, иначе в файл попадёт разметка самой страницы. Затем задаются тип содержимого, имя файла и кодировка. Для русских данных надёжнее всего UTF-8 с BOM: без метки старые версии Excel решат, что текст в кодировке Windows и покажут кракозябры.

Имя файла с кириллицей в заголовке Content-Disposition разные браузеры понимали по-разному, поэтому для совместимости имя лучше делать латиницей, например report_2008-06-23.xls.

ЗаголовкиVB.NET
Response.Clear()
Response.Buffer = True
Response.AddHeader("Content-Disposition", "attachment; filename=report.xls")
Response.ContentType = "application/vnd.ms-excel"
Response.ContentEncoding = System.Text.Encoding.UTF8
Response.BinaryWrite(System.Text.Encoding.UTF8.GetPreamble()) ' BOM для Excel

Выгрузка через GridView

Удобнее всего отдавать табличные данные элементом GridView: он уже умеет строить HTML-таблицу из DataTable или результата запроса. Элемент не обязательно размещать на странице. Его можно создать в коде, привязать к данным и попросить отрисовать себя в строку через HtmlTextWriter.

Такой подход позволяет повесить экспорт на обычную кнопку рядом с видимой таблицей. В примере данные для простоты собираются в DataTable в коде, в реальном проекте здесь будет запрос к базе.

Export.aspx.vbVB.NET
Imports System.Data
Imports System.IO
Imports System.Web.UI
Imports System.Web.UI.WebControls

Partial Class Export
    Inherits System.Web.UI.Page

    Private Function GetData() As DataTable
        Dim dt As New DataTable()
        dt.Columns.Add("Номер", GetType(Integer))
        dt.Columns.Add("Описание", GetType(String))
        For i As Integer = 1 To 100
            dt.Rows.Add(i, "Строка " & i)
        Next
        Return dt
    End Function

    Protected Sub btnExport_Click(sender As Object, e As EventArgs) Handles btnExport.Click
        Dim grid As New GridView()
        grid.DataSource = GetData()
        grid.DataBind()

        Response.Clear()
        Response.AddHeader("Content-Disposition", "attachment; filename=report.xls")
        Response.ContentType = "application/vnd.ms-excel"
        Response.ContentEncoding = System.Text.Encoding.UTF8
        Response.BinaryWrite(System.Text.Encoding.UTF8.GetPreamble())

        Using sw As New StringWriter(), hw As New HtmlTextWriter(sw)
            grid.RenderControl(hw)          ' таблица в HTML
            Response.Write(sw.ToString())
        End Using
        Response.End()
    End Sub
End Class
Если нужно выгрузить GridView, который уже стоит на странице внутри формы, ASP.NET бросит ошибку «Control must be placed inside a form tag with runat=server». Помогает пустое переопределение VerifyRenderingInServerForm в классе страницы.

Оформление и форматы ячеек

Раз Excel читает HTML, он понимает и часть CSS. Цвет фона заголовка, жирный шрифт и рамки, заданные стилями в ячейках, перенесутся в лист. Есть и специальное свойство mso-number-format, которое управляет форматом ячейки так же, как диалог «Формат ячеек».

Самая частая жалоба после первого запуска: пропали ведущие нули. Excel видит в ячейке 00123 число и превращает его в 123. То же происходит с длинными номерами счетов (они уходят в экспоненту) и с датами, которые Excel пытается распознать по своей локали. Решение: явно пометить такие столбцы текстовым форматом.

Стили для ExcelCSS
/* Вставляется в <style> перед таблицей */
.text   { mso-number-format: "\@"; }          /* текст, ноли сохраняются */
.money  { mso-number-format: "#,##0.00"; }    /* деньги с копейками */
.date   { mso-number-format: "dd\.mm\.yyyy"; } /* дата */
th      { background: #dce6f1; font-weight: bold; }

Ограничения подхода

Нужно честно понимать, что получается на выходе. Это не настоящий файл Excel, а HTML с расширением .xls. Начиная с Excel 2007 при открытии появляется предупреждение о несоответствии формата и расширения. Пользователь может нажать «Да», и всё откроется, но выглядит это настораживающе, а политика безопасности в компании может такие файлы вообще блокировать.

Кроме того, в таком файле нет нескольких листов, формул в привычном виде и надёжной типизации. Для внутренних отчётов приём по-прежнему годится, а для документов, которые уходят клиентам, лучше формировать настоящий xlsx.

  • Предупреждение Excel о формате при открытии.
  • Один лист, без формул и диаграмм.
  • Большие выгрузки занимают много памяти, так как HTML собирается целиком.
  • Типы ячеек угадываются Excel, если не задать mso-number-format.

Альтернатива: CSV

Если оформление не нужно, проще отдать CSV: значения через точку с запятой (её ожидает Excel с русской локалью), строки через перевод строки, ContentType text/csv и BOM в начале. Файл получится компактнее HTML, его без проблем прочитают и другие программы. Не забудьте экранировать значения, содержащие разделитель или кавычки: их заключают в двойные кавычки, а внутренние кавычки удваивают.

Как это делают сегодня

Сегодня настоящий xlsx на сервере формируют библиотеками ClosedXML, EPPlus или MiniExcel, которые работают без Office и поддерживают листы, формулы и стили. В ASP.NET Core файл отдают через return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "report.xlsx"). Для очень больших выгрузок используют потоковую запись, чтобы не держать весь документ в памяти.

Вопросы и ответы

Почему Excel ругается, что формат файла не совпадает с расширением?

Файл на самом деле HTML, а расширение .xls обещает двоичный формат. Это ограничение подхода, убрать предупреждение можно только генерацией настоящего xlsx.

Как сохранить ведущие нули в номерах?

Добавьте ячейкам стиль mso-number-format:"\@". Excel воспримет их как текст и не станет преобразовывать в число.

Можно ли поставить Excel на сервер и генерировать файлы через Interop?

Microsoft прямо не рекомендует автоматизацию Office на сервере: процессы зависают, плохо масштабируются и требуют лицензий. Используйте библиотеки для Open XML.

Читайте также