我有一个将 Excel 作为自定义 FileResult 返回的操作。我的解决方案基于ClosedXml库(内部使用 OpenXml)。我的 XlsxResult 类使用服务器上的只读 .xlsx 文件作为模板。然后它将模板传递到一个内存流中,该内存流被操作并使用 ClosedXml 保存回来。最后,内存流被写入响应。
这在 Cassini 和 IIS Express 上都可以正常工作,但在 azure 上部署时失败,没有任何错误。我遇到的唯一影响是发送到服务器的请求永远不会得到任何响应。我还在等待60分钟左右后发生的事情......
我的行动:
[OutputCache(Location= System.Web.UI.OutputCacheLocation.None, Duration=0)]
public FileResult Export(int year, int month, int day) {
var date = new DateTime(year, month, day);
var filename = string.Format("MyTemplate_{0:yyyyMMdd}.xlsx", date);
//return new FilePathResult("~/Content/templates/MyTemplate.xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
var result = new XlsxExportTemplatedResult("MyTemplate.xlsx", filename, (workbook) => {
var ws = workbook.Worksheets.Worksheet("My Export Sheet");
ws.Cell("B3").Value = date;
// Using a OpenXML's predefined formats (15 stands for date)
ws.Cell("B3").Style.NumberFormat.NumberFormatId = 15;
ws.Columns().AdjustToContents(); // You can also specify the range of columns to adjust, e.g.
return workbook;
});
return result;
}
我的文件结果
public class XlsxExportTemplatedResult : FileResult
{
// default buffer size as defined in BufferedStream type
private const int BufferSize = 0x1000;
public static readonly string TEMPLATE_FOLDER_LOCATION = @"~\Content\templates";
public XlsxExportTemplatedResult(string templateName, string fileDownloadName, Func<XLWorkbook, XLWorkbook> generate)
: base("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") {
this.TempalteName = templateName;
this.FileDownloadName = fileDownloadName;
this.Generate = generate;
}
public string TempalteName { get; protected set; }
public Func<XLWorkbook, XLWorkbook> Generate { get; protected set; }
protected string templatePath = string.Empty;
public override void ExecuteResult(ControllerContext context) {
templatePath = context.HttpContext.Server.MapPath(System.IO.Path.Combine(TEMPLATE_FOLDER_LOCATION, this.TempalteName));
base.ExecuteResult(context);
}
//http://msdn.microsoft.com/en-us/library/office/ee945362(v=office.11).aspx
protected override void WriteFile(System.Web.HttpResponseBase response) {
FileStream fileStream = new FileStream(templatePath, FileMode.Open, FileAccess.Read);
using (MemoryStream memoryStream = new MemoryStream()) {
CopyStream(fileStream, memoryStream);
using (var workbook = new XLWorkbook(memoryStream)) {
Generate(workbook);
workbook.Save();
}
// At this point, the memory stream contains the modified document.
// grab chunks of data and write to the output stream
Stream outputStream = response.OutputStream;
byte[] buffer = new byte[BufferSize];
while (true) {
int bytesRead = memoryStream.Read(buffer, 0, BufferSize);
if (bytesRead == 0) {
// no more data
break;
}
outputStream.Write(buffer, 0, bytesRead);
}
}
fileStream.Dispose();
}
static private void CopyStream(Stream source, Stream destination) {
byte[] buffer = new byte[BufferSize];
int bytesRead;
do {
bytesRead = source.Read(buffer, 0, buffer.Length);
destination.Write(buffer, 0, bytesRead);
} while (bytesRead != 0);
}
}
所以我错过了什么(显然我是)。
请注意:
- Azure 中没有缺少 dll,因为我使用 Windows Azure 工具 1.7 的 RemoteAccess 功能进行了检查
- 我的出口不是一项繁重的长期任务。
- 当我将操作更改为仅返回带有模板 xlsx 的 FilePathResult 时,它在 azure 上工作。但是我需要在返回文件之前对其进行处理,因为您可能会怀疑:-)
坦克。
更新: 在我广泛登录我的代码后,在 ClosedXml“保存”方法调用中执行挂起,没有错误。但仍然没有错误。WADLogsTable 的摘要:
- 从路径打开模板文件:E:\sitesroot\0\Content\templates\MyTemplate.xlsx
- 从路径打开的模板: E:\sitesroot\0\Content\templates\MyTemplate.xlsx 只是
- 将模板复制到可编辑的内存流。复制的字节数:15955,位置:15955
- 修改了内存中的excel文档。
- 当它调用 workbook.Save(); 时它挂起 这是一个 ClosedXml 方法调用。