1. ホーム
  2. c#

[解決済み] AJAX MVCによるExcelファイルのダウンロード

2022-11-24 08:55:52

質問

MVCの大規模なフォームがあります。

そのフォームのサブセットからデータを含むExcelファイルを生成できるようにする必要があります。

厄介なのは、これがフォームの残りの部分に影響を与えるべきではなく、AJAXを介してそれを行いたいことです。関連するように見える SO 上のいくつかの質問に出会いましたが、答えが何を意味するのかよくわかりません。

これは私が追い求めているものに最も近いようです。 asp-net-mvc ダウンローディング・エクセル - というのがありますが、対応がよくわかりませんし、もう数年前のものです。また、iframe を使用してファイルのダウンロードを処理する別の記事(もう見つかりません)も見つけましたが、MVC でこれを動作させる方法はよくわかりません。

私のエクセルファイルは、私が完全なポストバックをやっている場合はうまく返されますが、私はそれをMVCのAJAXで動作させることができません。

どのように解決するのですか?

AJAX呼び出しによってダウンロード用のファイルを直接返すことはできないので、代替のアプローチは、関連するデータをサーバーにポストするためにAJAX呼び出しを使用することです。その後、サーバー側のコードを使用してExcelファイルを作成できます(この部分が動作しているように聞こえますが、このためにEPPlusまたはNPOIを使用することをお勧めします)。

2016年9月更新

私の元の回答(以下)は3年以上前のものなので、私はもはやAJAX経由でファイルをダウンロードする際にサーバ上にファイルを作成しないので、私は更新しようと思ったが、私はそれがあなたの特定の要件に応じてまだいくつかの役に立つかもしれないので、元の回答を残しました。

私の MVC アプリケーションの一般的なシナリオは、ユーザーが構成したレポート パラメーター (日付範囲、フィルターなど) を持つ Web ページを介したレポートです。ユーザーがパラメーターを指定すると、サーバーにそれらを送信し、レポートが生成され (たとえば、出力として Excel ファイル)、次に、結果のファイルをバイト配列として TempData バケツにバイト配列として格納し、一意の参照を付けます。この参照は Json Result として AJAX 関数に渡され、その後、別のコントローラアクションにリダイレクトされて TempData からデータを抽出し、エンドユーザーのブラウザにダウンロードします。

より詳しく説明するために、MVCビューでモデルクラスにバインドされたフォームがあると仮定して、モデル ReportVM .

まず、投稿されたモデルを受け取るためのコントローラアクションが必要ですが、例としては以下のようになります。

public ActionResult PostReportPartial(ReportVM model){

   // Validate the Model is correct and contains valid data
   // Generate your report output based on the model parameters
   // This can be an Excel, PDF, Word file - whatever you need.

   // As an example lets assume we've generated an EPPlus ExcelPackage

   ExcelPackage workbook = new ExcelPackage();
   // Do something to populate your workbook

   // Generate a new unique identifier against which the file can be stored
   string handle = Guid.NewGuid().ToString();

   using(MemoryStream memoryStream = new MemoryStream()){
        workbook.SaveAs(memoryStream);
        memoryStream.Position = 0;
        TempData[handle] = memoryStream.ToArray();
   }      

   // Note we are returning a filename as well as the handle
   return new JsonResult() { 
         Data = new { FileGuid = handle, FileName = "TestReportOutput.xlsx" }
   };

}

MVCのフォームを上記のコントローラにポストし、レスポンスを受け取るAJAXの呼び出しは以下のようになります。

$ajax({
    cache: false,
    url: '/Report/PostReportPartial',
    data: _form.serialize(), 
    success: function (data){
         var response = JSON.parse(data);
         window.location = '/Report/Download?fileGuid=' + response.FileGuid 
                           + '&filename=' + response.FileName;
    }
})

ファイルのダウンロードを処理するためのコントローラアクションです。

[HttpGet]
public virtual ActionResult Download(string fileGuid, string fileName)
{   
   if(TempData[fileGuid] != null){
        byte[] data = TempData[fileGuid] as byte[];
        return File(data, "application/vnd.ms-excel", fileName);
   }   
   else{
        // Problem - Log the error, generate a blank file,
        //           redirect to another controller action - whatever fits with your application
        return new EmptyResult();
   }
}

必要であれば簡単に対応できる他の変更点として、ファイルの MIME タイプを 3 番目のパラメータとして渡すことで、1 つの Controller アクションでさまざまな出力ファイル形式を正しく扱えるようにすることができます。

これにより、物理的なファイルを作成してサーバーに保存する必要がなくなるため、管理ルーチンが不要になり、再びエンドユーザーにとってシームレスになります。

を使用することの利点に注意してください。 TempData ではなく Session は、一度 TempData が読み込まれるとデータがクリアされるので、大量のファイル要求がある場合には、メモリ使用量の点でより効率的になります。参照 TempDataのベストプラクティス .

オリジナル回答

AJAX呼び出しによってダウンロード用のファイルを直接返すことはできませんので、代替のアプローチは、関連するデータをサーバーにポストするためにAJAX呼び出しを使用することです。次に、サーバー側コードを使用してExcelファイルを作成できます(この部分が動作しているように聞こえますが、これにはEPPlusまたはNPOIを使用することをお勧めします)。

ファイルがサーバー上に作成されたら、AJAX呼び出しの戻り値としてファイルへのパス(または単にファイル名)を返し、JavaScriptの window.location をこの URL に設定すると、ブラウザにファイルをダウンロードするように要求します。

エンドユーザーの観点からは、リクエストが発生したページを離れることがないため、ファイルのダウンロード操作はシームレスに行われます。

以下は、これを実現するためのajax呼び出しの簡単な工夫された例です。

$.ajax({
    type: 'POST',
    url: '/Reports/ExportMyData', 
    data: '{ "dataprop1": "test", "dataprop2" : "test2" }',
    contentType: 'application/json; charset=utf-8',
    dataType: 'json',
    success: function (returnValue) {
        window.location = '/Reports/Download?file=' + returnValue;
    }
});

  • url パラメータは、あなたのコードがExcelファイルを作成するController/Actionメソッドです。
  • データ パラメータには、フォームから抽出される json データが含まれます。
  • 戻り値 は新しく作成されたExcelファイルのファイル名となります。
  • window.location コマンドは、実際にダウンロード用のファイルを返すController/Actionメソッドにリダイレクトします。

ダウンロードアクションのコントローラメソッドのサンプルは次のようになります。

[HttpGet]
public virtual ActionResult Download(string file)
{   
  string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
  return File(fullPath, "application/vnd.ms-excel", file);
}