Загрузите файл .xlsx с помощью Response.TransmitFile()

Я работаю над некоторым кодом, который генерирует электронную таблицу Excel, а затем загружает ее пользователю. Я использую ExcelPackage для создания файла.

Генерация работает нормально. Я могу открыть сгенерированные файлы с помощью Excel 2007 без проблем. Но, у меня возникли проблемы с загрузкой файла с помощью Response.TransmitFile().

Сейчас у меня есть следующий код:

//Generate the file using ExcelPackage
string fileName = generateExcelFile(dataList, "MyReportData");

Response.AddHeader("content-disposition", "attachment;filename=FileName.xls");
Response.ContentType = "application/vnd.xls"
Response.Charset = "";
Response.TransmitFile(fileName);

Когда Excel 2007 открывает файл, загруженный, как указано выше, он дает предупреждение "формат файла не соответствует расширению". После нажатия на предупреждение, Excel отображает содержимое XML файла с исходным текстом.

Если я изменил расширение файла, например

Response.AddHeader("content-disposition", "attachment;filename=FileName.xlsx");

В Excel 2007 появляется сообщение "Неиспользуемый контент в файле" в Excel, за которым следует диалог, который предлагает найти конвертер в Интернете. Если я нажму "нет" в этом диалоговом окне, Excel сможет загрузить данные.

Я также экспериментировал с разными типами MIME, такими как application/vnd.ms-excel и application/vnd.openxmlformats-officedocument.spreadsheetml.sheet, в сочетании с расширениями файлов .xls и .xlsx. Все комбинации приводят к одному из двух вариантов поведения, упомянутых выше.

Какова правильная комбинация расширения файла и типа MIME для использования в этом сценарии? Что еще может вызвать этот отказ, кроме неправильного типа или расширения MIME?

FYI, это происходит с помощью встроенного веб-сервера разработки Visual Studio. Я еще не пробовал это с IIS.

Ответ 1

Я не могу точно сказать, что с вашим подходом что-то не так, но я просто расскажу о некоторых наблюдениях от того, что сделаю что-то подобное.

Заголовки - это Pascal Case, большинство браузеров не должно волновать, но я бы изменил ваш контент-расположение на Content-Disposition. Изменение Charset не должно быть необходимым или релевантным. Ваш тип контента должен быть точным, я бы использовал только application/vnd.openxmlformats-officedocument.spreadsheetml.sheet и .xlsx, если это на самом деле содержимое файла, в противном случае придерживаться application/vnd.ms-excel и .xls.

Еще одна вещь, которую вы должны рассмотреть, - это отправить браузеру Content-Length:

Response.AddHeader("Content-Length", new System.IO.FileInfo("FileName.xlsx").Length);

Также вы пробовали это с несколькими браузерами? Просто интересно, если это проблема, зависящая от поставщика.

Как последнее усилие, вы можете настроить Content-Type на приложение/октет-поток, и любой браузер должен предложить его загрузить, а затем большинство браузеров позволят вам открыть его после его загрузки на основе расширения.

Ответ 2

используйте этот

HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=\"filename + ".zip" + "\"");
                Response.TransmitFile(zipPath);
                Response.Flush();
                Response.Close();
                Response.End();

в вашем коде

Response.AddHeader("content-disposition", "attachment;filename=\FileName.xlsx\");

Ответ 3

Попробуйте это

public void DataTableToExcel(DataTable dt, string Filename)
{
    MemoryStream ms = DataTableToExcelXlsx(dt, "Sheet1");
    ms.WriteTo(HttpContext.Current.Response.OutputStream);
    HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
    HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + Filename);
    HttpContext.Current.Response.StatusCode = 200;
    HttpContext.Current.Response.End();
}

public static MemoryStream DataTableToExcelXlsx(DataTable table, string sheetName)
{
    MemoryStream result = new MemoryStream();
    ExcelPackage excelpack = new ExcelPackage();
    ExcelWorksheet worksheet = excelpack.Workbook.Worksheets.Add(sheetName);
    int col = 1;
    int row = 1;
    foreach (DataColumn column in table.Columns)
    {
        worksheet.Cells[row, col].Value = column.ColumnName.ToString();
        col++;
    }
    col = 1;
    row = 2;
    foreach (DataRow rw in table.Rows)
    {
        foreach (DataColumn cl in table.Columns)
        {
            if (rw[cl.ColumnName] != DBNull.Value)
                worksheet.Cells[row, col].Value = rw[cl.ColumnName].ToString();
            col++;
        }
        row++;
        col = 1;
    }
    excelpack.SaveAs(result);
    return result;
}