Azure上的自定义FileResult:浏览器永远等待

时间:2012-08-23 14:50:00

标签: azure asp.net-mvc-4 openxml closedxml

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

}

所以我错过了一些东西(显然我是)。

请注意:

  1. Azure中没有丢失dll,因为我使用了Windows Azure Tools 1.7的RemoteAccess功能进行了检查
  2. 我的出口并不是一项繁重的长期任务。
  3. 当我将动作更改为仅使用模板xlsx返回FilePathResult时,它在azure上工作。但是我需要在返回之前处理文件,因为你可能会怀疑: - )
  4. 坦克。

      

    更新   在我的代码中广泛记录后,执行挂起,并且在ClosedXml“保存”方法调用中没有错误。但仍然没有错误。摘自WADLogsTable:

         
        
    • 从路径打开模板文件:   E:\ sitesroot \ 0 \ Content \ templates \ MyTemplate.xlsx
    •   
    • 从路径打开模板:   E:\ sitesroot \ 0 \ Content \ templates \ MyTemplate.xlsx只是
    •   
    • 将模板复制到可编辑的内存流。复制的字节数:15955,   位置:15955
    •   
    • 修改了内存中的excel文档。
    •   
    • 此处它在调用workbook.Save()时挂起这是一个ClosedXml方法调用。
    •   

1 个答案:

答案 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方法。