[解決済み] AJAX MVCによるExcelファイルのダウンロード
質問
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);
}
関連
-
[解決済み】「未割り当てのローカル変数を使用」とはどういう意味ですか?
-
[解決済み] 関数を終了するには?
-
[解決済み] どのラジオボタンが選択されているかをjQueryで知るにはどうしたらよいですか?
-
[解決済み] Microsoft Officeをインストールせずに、C#でExcel(.XLSおよび.XLSX)ファイルを作成するにはどうすればよいですか?
-
[解決済み] jQueryを使ったAjaxリクエストの中断
-
[解決済み] jQuery Ajax呼び出し後のリダイレクトリクエストを管理する方法
-
[解決済み] jQuery AJAX送信フォーム
-
[解決済み] ファイルアップロード ASP.NET MVC 3.0
-
[解決済み] jQuery Ajax ファイルアップロード
-
[解決済み] ajaxポストからのファイルダウンロードを処理する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】エラー。「戻り値を変更できません」 C#
-
[解決済み】"出力タイプがクラスライブラリのプロジェクトは直接起動できない"
-
[解決済み】Ajax処理で「無効なJSONプリミティブ」と表示される件
-
[解決済み] 保護レベルによりアクセス不能になりました。
-
[解決済み】リソースの読み込みに失敗した:ステータス500(内部サーバーエラー)のサーバーの応答)
-
[解決済み】WPFでXamlファイルにコメントを追加する方法は?
-
[解決済み】取り消せないメンバはメソッドのように使えない?
-
[解決済み】ファイルへの読み書きの際に共有違反のIOExceptionが発生する C#
-
[解決済み】インデックスが範囲外でした。コレクションパラメータname:indexのサイズより小さく、非負でなければなりません。
-
[解決済み】WebResource.axdとは何ですか?