AJAX 呼び出しを介してダウンロード用のファイルを直接返すことはできないため、別の方法として、AJAX 呼び出しを使用して関連データをサーバーにポストする方法があります。次に、サーバー側のコードを使用して Excel ファイルを作成できます (この部分が機能しているように聞こえますが、これには EPPlus または NPOI を使用することをお勧めします)。
2016 年 9 月の更新
私の元の回答(以下)は3年以上前のものだったので、AJAX経由でファイルをダウンロードするときにサーバー上にファイルを作成しなくなったので更新すると思っていましたが、元の回答は残っています。あなたの特定の要件。
私の MVC アプリケーションの一般的なシナリオは、ユーザーが構成したレポート パラメーター (日付範囲、フィルターなど) を持つ Web ページを介してレポートを作成することです。ユーザーがサーバーに送信するパラメーターを指定すると、レポートが生成され (たとえば、Excel ファイルを出力として)、結果のファイルをTempData
一意の参照と共にバイト配列としてバケットに格納します。この参照は Json Result として 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 つの変更は、ファイルの MIME タイプを 3 番目のパラメーターとして渡すことです。これにより、1 つのコントローラー アクションがさまざまな出力ファイル形式を正しく処理できるようになります。
これにより、物理ファイルを作成してサーバーに保存する必要がなくなるため、ハウスキーピング ルーチンが不要になり、これもエンド ユーザーにとってシームレスになります。
を使用する利点は、データが読み取られるとクリアされるため、大量のファイル要求がある場合にメモリ使用量の点でより効率的であることに注意してTempData
くださいSession
。TempData のベスト プラクティスTempData
を参照してください。
元の回答
AJAX 呼び出しを介してダウンロード用のファイルを直接返すことはできないため、別の方法として、AJAX 呼び出しを使用して関連データをサーバーにポストする方法があります。次に、サーバー側のコードを使用して Excel ファイルを作成できます (この部分が機能しているように聞こえますが、これには EPPlus または NPOI を使用することをお勧めします)。
サーバー上でファイルが作成されたら、AJAX 呼び出しへの戻り値としてファイルへのパス (またはファイル名のみ) を返し、JavaScriptwindow.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コマンドは、ダウンロードするファイルを実際に返す 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);
}