asp.net-mvc - OpenXml 和 HttpResponse.OutputStream

标签 asp.net-mvc openxml httpresponse openxml-sdk

我有一个 Asp.Net Mvc 应用程序。在此应用程序中,我具有将数据从数据库下载到 Excel 文件的功能(使用 OpenXml Sdk)。现在可以了。但当数据量较大时,从用户请求到响应下载窗口的时间变为10分钟以上。这是因为两个漫长的过程:

  1. 从 MSSQL 服务器获取数据。
  2. 正在服务器内存中生成 Excel 文档。 (Excel文档完成后才开始下载)

通过使用DataReader解决了第一个问题。现在,Excel 文件的生成在用户请求到达网络服务器后立即开始。

为了解决第二个问题,我们需要在 HttpResponse.OutputStream 上生成 Excel 文档,但该流不可查找,并且在开始之前生成失败。

有人知道可以帮助解决此问题的解决方法吗?

我的生成函数示例:

    public void GenerateSpreadSheetToStream(IDataReader dataReader, Stream outputStream)
    {
        var columnCaptions =                FillColumnCaptionsFromDataReader(dataReader.GetSchemaTable());
//fails on next line with exception "Cannot open package because FileMode or FileAccess value is not valid for the stream."
        using (var spreadsheetDocument = SpreadsheetDocument.Create(outputStream, SpreadsheetDocumentType.Workbook)) 
        {
            spreadsheetDocument.AddWorkbookPart();
            var workSheetPart = spreadsheetDocument.WorkbookPart.AddNewPart<WorksheetPart>();
            OpenXmlWriter writer;
            using (writer = OpenXmlWriter.Create(workSheetPart))
            {
                using (writer.Write(new Worksheet()))
                {

                    using (writer.Write(new SheetData()))
                    {
                        using (writer.Write(w => 
                            w.WriteStartElement(new Row(), new[] {new OpenXmlAttribute("r", null, 1.ToString(CultureInfo.InvariantCulture))})))
                        {
                            var cells =
                                columnCaptions.Select(caption => new Cell()
                                    {
                                        CellValue = new CellValue(caption.Item2),
                                        DataType = CellValues.String
                                    });
                            foreach (var cell in cells)
                            {
                                writer.WriteElement(cell);
                            }
                        }
                        var i = 2;
                        while (dataReader.Read())
                        {
                            var oxa = new[] { new OpenXmlAttribute("r", null, i.ToString(CultureInfo.InvariantCulture)) };
                            using (writer.Write(w => w.WriteStartElement(new Row(), oxa)))
                            {
                                var cells =
                                    columnCaptions.Select(
                                        (c, j) =>
                                        new Cell
                                            {
                                                CellValue = new CellValue(dataReader[c.Item1].ToString()),
                                                DataType = CellValues.String,
                                                CellReference = new StringValue(GetSymbolByCellNumber(j))
                                            });
                                foreach (var cell in cells)
                                {
                                    writer.WriteElement(cell);
                                }
                            }
                            i++;
                        }
                    }
                }
            }
            using (writer = OpenXmlWriter.Create(spreadsheetDocument.WorkbookPart))
            {
                using (writer.Write(new Workbook()))
                {
                    using (writer.Write(new Sheets()))
                    {
                        var sheet = new Sheet
                        {
                            Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(workSheetPart),
                            SheetId = 1,
                            Name = SheetName
                        };
                        writer.WriteElement(sheet);
                    }
                }
            }
        }
    }
    private static string GetSymbolByCellNumber(int number)
    {
        var r = number/26;
        var s = (char) ((number%26) + 65);
        return new string(s, r);
    }

我的 FileStreamResultWithTransformation(用于使用 HttpResponse.OutputStream):

public class FileStreamResultWithTransformation : FileResult
{
    private readonly Action<Stream> _action;
    public FileStreamResultWithTransformation(Action<Stream> action, string contentType, string fileName) : base(contentType)
    {
        _action = action;
        FileDownloadName = fileName;
    }

    protected override void WriteFile(HttpResponseBase response)
    {
        response.BufferOutput = false;
        _action(response.OutputStream); ->> it fails there  
    }
}

堆栈跟踪:

[IOException: Cannot open package because FileMode or FileAccess value is not valid for the stream.]
System.IO.Packaging.Package.ValidateModeAndAccess(Stream s, FileMode mode, FileAccess access) +784533
System.IO.Packaging.Package.Open(Stream stream, FileMode packageMode, FileAccess packageAccess, Boolean streaming) +89
System.IO.Packaging.Package.Open(Stream stream, FileMode packageMode, FileAccess packageAccess) +10
DocumentFormat.OpenXml.Packaging.OpenXmlPackage.CreateCore(Stream stream) +192
DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Create(Stream stream, SpreadsheetDocumentType type, Boolean autoSave) +215
DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Create(Stream stream, SpreadsheetDocumentType type) +44
-------.GenerateSpreadSheetToStream(IDataReader dataReader, Stream outputStream) in d:\Work\Epsilon\development\Web\trunk\Sources\Epsilon.DocumentGenerator\XlsXGenerator.cs:119

最佳答案

在我看来,这个问题无法解决。写入完成后,OpenXmlWriter 在流的不同位置进行查找、读取和写入,如果没有此操作,xlsx 文件就会损坏。 我认为,OpenXml 库的设计有问题。

关于asp.net-mvc - OpenXml 和 HttpResponse.OutputStream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13049215/

相关文章:

c# - 使用自定义 XML 部分隐藏 Word 内容控件

C# Open XML SDK 2.0 Excel 电子表格 - 从字符串数组加载单元格范围

python-2.7 - 使用 Python 中的请求库测量 HTTP 响应时间。我做对了吗?

jdbc - 带有 JDBC 结果集变量和计数器变量的 JMeter 嵌套变量引用

asp.net - 用户角色 - 为什么不在 session 中存储?

c# - 在 OpenXML 中使用 XML 映射导入 xml

c# - Mono 3.0/Debian/asp.net - 找不到方法 : 'System. Configuration.IConfigurationSectionHandler.Create

java - PrintWriter 输出到 body 标记内的 jsp 页面

asp.net - Microsoft.CodeDom.Providers.DotNetCompilerPlatform v1.0.6

asp.net-mvc - 从 n 层 ASP.Net MVC 应用程序的服务层处理或抛出异常的合适方法是什么?