2019年4月25日木曜日

ASP.NET MVCでファイルダウンロード後にViewが表示できないときの対処方法。


オフィス狛 技術部のJoeです。

最近、ASP.NET MVCで開発されたWebシステムの改修プロジェクトをお手伝いしたのですが、ASP.NET MVCでの開発が初めてだったので、色々と戸惑いが多かったです。
その中でも、あるエラーについての対処方法をご紹介したいと思います。

今回のプロジェクトでは、ControllerからViewを表示したり、別のアクションを起こす場合は、主に下記のActionResultオブジェクトを使っていました。

① 呼び出し元のViewを表示する

return View();

② 指定したViewを表示する

return View("~/Views/Test/index.cshtml");

③ 指定したControllerのアクションを実行する

return RedirectToAction(MethodName.Index, ControllerName.Test);

ところが、ファイルをダウンロードした後に上記のActionResultオブジェクトを使用すると、Exceptionが発生してしまいました。

[ C#(Response.WriteFileメソッドを使用してサーバ上のExcelファイルをダウンロード) ]
// Excelファイルをダウンロード
var DownloadFile = Server.MapPath("~/Reports/Download.xlsx");
long offset = 0;
long size = new FileInfo(DownloadFile).Length;
Response.Clear();
Response.ContentEncoding = Encoding.GetEncoding("UTF-8");
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";  // これはExcel
Response.AppendHeader("content-disposition", "attachment; filename=" + Server.UrlEncode("ダウンロード.xlsx"));
Response.WriteFile(DownloadFile, offset, size);
Response.End();

// 呼び出し元のViewを表示する(①のパターン)
return View();

[ エラー内容 ]
HTTP ヘッダーの送信後にサーバーでヘッダーを追加できません。

②でも同じエラーになります。

実は今回、CSRF対策としてView側で「Html.AntiForgeryToken」ヘルパーを呼び出していました。
ファイルをダウンロードしているので、「Response.End()」の時点でクライアントにHTTPヘッダーが送信されています。
「return View(…)」でViewを返した際に、View側で「Html.AntiForgeryToken」ヘルパーがCookieを設定しようとして、エラーになってしまいました。

では③「RedirectToAction」を試してみると

[ エラー内容 ]
HTTP ヘッダーを送信後はリダイレクトできません。

こちらはエラーのとおり、リダイレクトができないようです。


【対処方法1】何も返さない
何も返さなければいいということで、以下に修正してExceptionを回避できました。
return new EmptyResult();

ちなみに以下でも同じ動きです。MVCが判断して「return new EmptyResult();」を返してくれます。
return null;

【対処方法2】ダウンロードするファイルを返す
こちらは「return File」でファイルを返します。(「Response.WriteFileメソッド」を使用しません)
なんだかスッキリしてますし、ダウンロード後に何か処理が無ければこちらのほうが良いですね。
[ C# ]
var DownloadFile = Server.MapPath("~/Reports/ManuallyRecord.xlsx");
var contentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";  // Excel
return File(DownloadFile, contentType, Server.UrlEncode("ダウンロード.xlsx"));

ActionResultオブジェクトだけでもいろいろなパターンがあって、まだまだ覚えることがたくさんありそうです。


,

0 件のコメント:

コメントを投稿