我有一个将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;
}
我的FileResult
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);
}
}
所以我错过了一些东西(显然我是)。
请注意:
坦克。
更新 在我的代码中广泛记录后,执行挂起,并且在ClosedXml“保存”方法调用中没有错误。但仍然没有错误。摘自WADLogsTable:
- 从路径打开模板文件: E:\ sitesroot \ 0 \ Content \ templates \ MyTemplate.xlsx
- 从路径打开模板: E:\ sitesroot \ 0 \ Content \ templates \ MyTemplate.xlsx只是
- 将模板复制到可编辑的内存流。复制的字节数:15955, 位置:15955
- 修改了内存中的excel文档。
- 此处它在调用workbook.Save()时挂起这是一个ClosedXml方法调用。
答案 0 :(得分:1)
我遇到了与你完全相同的错误情况。我不能在你的具体情况下提供修复,而且我知道你改变了轨道,但在经历了你面对的同样令人沮丧的步骤之后,我想为你(或其他人)的答案“铺平道路”
在Visual Studio中放入包管理器控制台并使用MVC好东西(路由)安装Elmah:
Install-Package elmah.MVC
现在,在您的根web.config中,更新您的Elmah条目。它可能在文件的末尾,看起来像这样:
<elmah></elmah>
更新那个坏男孩以允许远程访问并设置日志路径:
<elmah>
<security allowRemoteAccess="1" />
<errorLog type="Elmah.XmlFileErrorLog, Elmah" logPath="~/app_data/elmah" />
</elmah>
现在,将其推送到Azure。
最后,访问您的网站,强制显示错误,然后导航到http://your-site-here.azurewebsites.net/elmah,您就会看到错误的确切原因。
Elmah太棒了。
懦弱的忏悔:我的错误不在第三方代码中,结果是在我的连接字符串中,我没有将MultipleActiveResultsSets
设置为true 。我必须做的另一个修复是在调用ToList()之后将我的实体传递给该库中的一个内部方法,将其保留为IQueryable borked方法。