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. Windows Azure Tools 1.7 の RemoteAccess 機能を使用して確認したため、Azure から欠落している dll はありません。
  2. 私のエクスポートは、長時間実行される重いタスクではありません。
  3. テンプレート xlsx を使用して FilePathResult を返すようにアクションを変更すると、紺碧で動作しました。しかし、あなたが疑うかもしれないように、ファイルを返す前にファイルを処理する必要があります:-)

タンク。

更新: コードに広範囲にログインした後、ClosedXml の "Save" メソッド呼び出しで実行がエラーなしでハングします。しかし、まだエラーはありません。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に移動すると、エラーの正確な原因が表示されます。

エルマはとても素晴らしいです。

愚かな告白:MultipleActiveResultsSets私にとってのエラーはサードパーティのコードではなく、true に設定していなかった接続文字列にあることが判明しました。私がしなければならなかったもう 1 つの修正は、ToList() をそのライブラリの内部メソッドの 1 つに呼び出した後にエンティティを渡し、IQueryable がメソッドを中断したままにしておくことでした。

于 2013-01-26T19:02:04.930 に答える