Asp.Net Mvc アプリケーションがあります。このアプリケーションには、データベースから Excel ファイル (OpenXml Sdk を使用) にデータをダウンロードする機能があります。それは今動作します。ただし、データが大きい場合、ユーザー リクエストからダウンロード ウィンドウでの応答までの時間は 10 分以上になります。これは、次の 2 つの長いプロセスが原因です。
- MSSQL サーバーからデータを取得しています。
- サーバー上のメモリに Excel ドキュメントを生成しています。(ダウンロードはエクセル文書が完成した時点で開始されます)
最初の問題は、DataReader を使用して解決されました。これで、Web サーバーへのユーザー リクエストが発生した直後に、Excel ファイルの生成が開始されます。
2 番目の問題を解決するには、HttpResponse.OutputStream で Excel ドキュメントを生成する必要がありますが、このストリームは Seekable ではなく、生成を開始する前に失敗します。
この問題を解決するのに役立つ回避策を知っている人はいますか?
私の生成関数のサンプル:
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: FileMode または FileAccess の値がストリームに対して有効でないため、パッケージを開けません
。
ストリーム ストリーム、FileMode packageMode、FileAccess packageAccess、ブール ストリーミング) +89
System.IO.Packaging.Package.Open(ストリーム ストリーム、FileMode packageMode、FileAccess packageAccess) +10
DocumentFormat.OpenXml.Packaging.OpenXmlPackage.CreateCore(ストリーム ストリーム) +192
DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Create(ストリーム ストリーム、SpreadsheetDocumentType タイプ、Boolean autoSave) +215
DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Create(ストリーム ストリーム、SpreadsheetDocumentType タイプ) +44
-------.GenerateSpreadSheetToStream(IDataReader dataReader, Stream outputStream) in d:\Work\Epsilon\development\Web\trunk\Sources\Epsilon.DocumentGenerator\XlsXGenerator.cs:119