2

我有一个将 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);
    }

}

所以我错过了什么(显然我是)。

请注意:

  1. Azure 中没有缺少 dll,因为我使用 Windows Azure 工具 1.7 的 RemoteAccess 功能进行了检查
  2. 我的出口不是一项繁重的长期任务。
  3. 当我将操作更改为仅返回带有模板 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 方法调用。
4

1 回答 1

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 使该方法失效。

于 2013-01-26T19:02:04.930 回答