AJAX呼び出しを介してダウンロード用のファイルを直接返すことはできないため、別のアプローチは、AJAX呼び出しを使用して関連データをサーバーに投稿することです。その後、サーバー側のコードを使用してExcelファイルを作成できます(これにはEPPlusまたはNPOIを使用することをお勧めしますが、この部分が機能しているように見えます)。
2016年9月更新
私の元の答え(下記)は3年以上前のものだったので、AJAX経由でファイルをダウンロードするときにサーバー上にファイルを作成しなくなったので更新するつもりでしたが、特定の要件。
私のMVCアプリケーションの一般的なシナリオは、ユーザーが構成したレポートパラメーター(日付範囲、フィルターなど)があるWebページを介したレポートです。ユーザーがサーバーに投稿するパラメーターを指定すると、レポートが生成され(たとえば、出力としてのExcelファイル)、結果のファイルTempData
が一意の参照を持つバケットにバイト配列として保存されます。この参照は、Jsonの結果としてAJAX関数に返され、その後、別のコントローラーアクションにリダイレクトされTempData
て、エンドユーザーのブラウザーからデータを抽出し、ブラウザーにダウンロードします。
これを詳しく説明するために、Modelクラスにバインドされたフォームを持つMVCビューがあると想定して、Modelを呼び出します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();
}
}
必要に応じて簡単に対応できるもう1つの変更は、1つのコントローラーアクションがさまざまな出力ファイル形式を正しく処理できるように、ファイルのMIMEタイプを3番目のパラメーターとして渡すことです。
これにより、物理ファイルを作成してサーバーに保存する必要がなくなり、ハウスキーピングルーチンは不要になり、エンドユーザーにとってシームレスになります。
注、使用しての利点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ファイルを作成するコントローラー/アクションメソッドです。
- dataパラメータには、フォームから抽出されるjsonデータが含まれています。
- returnValueは、新しく作成したExcelファイルのファイル名になります。
- window.locationのを実際にダウンロードするファイルを返すコントローラ/アクションメソッドへのコマンドリダイレクト。
ダウンロードアクションのサンプルコントローラメソッドは次のようになります。
[HttpGet]
public virtual ActionResult Download(string file)
{
string fullPath = Path.Combine(Server.MapPath("~/MyFiles"), file);
return File(fullPath, "application/vnd.ms-excel", file);
}