Asp .net / c# Экспорт данных в Excel - PullRequest
0 голосов
/ 16 января 2020

У меня старое устаревшее веб-приложение. Недавно мы переместили его со старого сервера Windows 2008 r2 на новый сервер Windows 2019, и обнаружилось несколько проблем. Я работал с большинством из них, но есть один, который все еще вызывает у меня некоторые проблемы. Это веб-приложение должно экспортировать данные в формате DataTable в лист Excel для просмотра пользователем. Однако при экспорте файла Excel они получают это сообщение

Формат файла и расширение файла «Report.xls» не совпадают. Файл может быть поврежден или небезопасен. Если вы не доверяете его источнику, не открывайте его. Вы все равно хотите его открыть?

Если они нажмут "да", тогда он выдаст другое сообщение

Файл поврежден и не может быть открыт.

Не было никаких проблем со старым сервером r2 2008 года.

Я пытался изменить Response.ContentType = "application/vnd.xls"; на Response.ContentType = "application/vnd.ms-excel";, а также Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";, и я все еще получаю то же самое Сообщения. Мне нужно предоставить лист Excel, и я не могу заплатить за пакет Excel.

Вот код, который генерирует файл Excel:

public void Create_Spreadsheet(string sheetField, string[] arrExcelColumns, DataTable table)
{
    using (MemoryStream stream = new MemoryStream())
    {
        string pathToXsl = Server.MapPath(relToXsl);
        string reportFileName = "Report.xls";
        string fieldName = "Field";
        string worksheetName = "Sheet";
        string prevWorksheet = "";
        DataView dv = new DataView();
        DataTable dt = new DataTable();

        dt = table;

        // sort data for displaying with worksheets
        dv = dt.DefaultView;
        if (dv.Table.Columns.Contains(sheetField)) dv.Sort = sheetField;
        DataTable dtSorted = dv.ToTable();

        // get columns array
        ArrayList arrColumns = new ArrayList();
        for (int k = 0; k < dtSorted.Columns.Count; ++k)
        {
            if (Array.IndexOf(arrExcelColumns, dtSorted.Columns[k].ColumnName) >= 0)
                arrColumns.Add(dtSorted.Columns[k].ColumnName);
        }

        XmlWriterSettings settings = new XmlWriterSettings();
        settings.Indent = true;
        settings.Encoding = System.Text.Encoding.UTF8;

        StringBuilder sb = new StringBuilder();

        // Create the XmlWriter object and write some content.
        XmlWriter xmlWriter = XmlWriter.Create(sb, settings);
        xmlWriter.WriteStartDocument();

        // Write our first XML header (root)
        xmlWriter.WriteStartElement("Root");

        if (dtSorted.Rows.Count > 0)
        {
            Regex rx = new Regex(@"^[a-zA-z_]+");
            foreach (DataRow dr in dtSorted.Rows)
            {
                worksheetName = arrColumns.Contains(sheetField) && !String.IsNullOrEmpty(dr[sheetField].ToString()) ? dr[sheetField].ToString() : "New";
                if (!rx.IsMatch(worksheetName)) worksheetName = "_" + worksheetName;

                if (prevWorksheet != worksheetName)
                {
                    // end write worksheet
                    if (!String.IsNullOrEmpty(prevWorksheet)) xmlWriter.WriteEndElement();
                    // begin write worksheet
                    xmlWriter.WriteStartElement(worksheetName);
                }

                // begin write record
                xmlWriter.WriteStartElement("Record");


                foreach (Object o in arrColumns)
                {
                    fieldName = o.ToString();
                    //if (fieldName != sheetField)    // don't display worksheet field
                    xmlWriter.WriteElementString(fieldName, dr[fieldName].ToString());
                }

                // end write record
                xmlWriter.WriteEndElement();

                prevWorksheet = worksheetName;
            }

            // end write last worksheet
            xmlWriter.WriteEndElement();
        }
        else
        {
            // begin write worksheet
            xmlWriter.WriteStartElement(worksheetName);
            // begin write record
            xmlWriter.WriteStartElement("Record");

            foreach (Object o in arrColumns)
            {
                fieldName = o.ToString();
                xmlWriter.WriteElementString(fieldName, "");
            }
            //xmlWriter.WriteElementString("Result", "No records found.");

            // end write record
            xmlWriter.WriteEndElement();
            // end write worksheet
            xmlWriter.WriteEndElement();
        }

        // end root
        xmlWriter.WriteEndElement();
        // Finilize the XML document by writing any required closing tag.
        xmlWriter.WriteEndDocument();
        xmlWriter.Flush();

        // Load the style sheet.
        XslCompiledTransform xslt = new XslCompiledTransform();
        xslt.Load(pathToXsl);

        // Create the writer.
        XmlWriterSettings settings2 = new XmlWriterSettings();
        settings2.Indent = true;
        settings2.IndentChars = "\t";
        XmlWriter writer = XmlWriter.Create(stream, settings2);

        XmlReader xmlReader = XmlReader.Create(new StringReader(sb.ToString()));
        xmlReader.MoveToContent();

        // Execute the transformation.
        xslt.Transform(xmlReader, writer);

        writer.Close();
        xmlReader.Close();

        xmlWriter.Close();

        // Convert the memory stream to an array of bytes.
        byte[] byteArray = stream.ToArray();

        // Send the XML file to the web browser for download.
        Response.Clear();
        //Response.AppendHeader("Content-Disposition", "filename=Report.xml");
        //Response.AppendHeader("Content-Length", byteArray.Length.ToString());
        //Response.ContentType = "application/octet-stream";

        //Response.ContentType = "application/vnd.xls";
        Response.ContentType = "application/vnd.ms-excel";
        //Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
        Response.AddHeader("Content-Disposition", "attachment; filename=" + reportFileName);
        Response.AppendHeader("Content-Length", byteArray.Length.ToString());

        Response.BinaryWrite(byteArray);

        Response.End();
    }
}

Я не являюсь уверен, где дела идут не так, или что изменилось. Это новый сервер Windows 2019 (на котором не установлен офис), а код Asp .net / C# не имеет решения (он был создан в старом стиле "веб-сайта") , Любая помощь будет принята с благодарностью! дайте мне знать, если что-нибудь еще понадобится.

Edit:

с использованием библиотеки EPPlus и следующего кода:

public void ExportToExcel(DataTable dt, string FileName)
{
    //create a new byte array       
    byte[] bin;

    //create a new excel document
    using (ExcelPackage excelPackage = new ExcelPackage())
    {
        //create a new worksheet
        ExcelWorksheet ws = excelPackage.Workbook.Worksheets.Add(FileName);

        //add the contents of the datatable to the excel file
        ws.Cells["A1"].LoadFromDataTable(dt, true);

        //auto fix the columns
        ws.Cells[ws.Dimension.Address].AutoFitColumns();

        //loop all the columns
        for (int col = 1; col <= ws.Dimension.End.Column; col++)
        {
            //make all columns just a bit wider, it would sometimes not fit
            ws.Column(col).Width = ws.Column(col).Width + 1;

            var cell = ws.Cells[1, col];

            //make the text bold
            cell.Style.Font.Bold = true;

            //make the background of the cell gray
            var fill = cell.Style.Fill;
            fill.PatternType = ExcelFillStyle.Solid;
            fill.BackgroundColor.SetColor(ColorTranslator.FromHtml("#BFBFBF"));

            //make the header text upper case
            cell.Value = ((string)cell.Value).ToUpper();
        }

        //convert the excel package to a byte array
        bin = excelPackage.GetAsByteArray();
    }

    //clear the buffer stream
    Response.ClearHeaders();
    Response.Clear();
    Response.Buffer = true;

    //set the correct contenttype
    Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";

    //set the correct length of the data being send
    Response.AddHeader("content-length", bin.Length.ToString());

    //set the filename for the excel package
    Response.AddHeader("content-disposition", "attachment; filename=\"" + FileName + ".xlsx\"");

    //send the byte array to the browser
    Response.OutputStream.Write(bin, 0, bin.Length);

    //cleanup
    Response.Flush();
    HttpContext.Current.ApplicationInstance.CompleteRequest();
}

теперь выдает ошибку:

C: \ Users ... \ AppData \ Local \ Temp \ RoIFPfvQ.xlsx.part не удалось сохранить, поскольку исходный файл не может быть прочитан.

однако, если я пересылаю RDP на веб-сервер и go на веб-страницу, загружаю пакет и перемещаю его на локальный компьютер (поскольку Excel не находится на веб-сервере), файл открывается просто отлично. Что мне не хватает? где эта попытка создать xlsx.part, и может ли быть содержимое удалено / удалено до того, как файл действительно будет сохранен / загружен?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...