ASP.NET MVC2 の話。
下記のようなアクションがあったとして、
public class HogeController : Controller {
public ActionResult DownloadAction() {
...
return File(bytes, "image/png", "画像1.png");
}
http://host/Hoge/Download にジャンプすると、「画像1.png」の画像ファイルのダウンロードが始まる。
ところが、Internet Explorer ( 以下 IE ) だと、ダウンロードダイアログに表示されるファイル名が「8.png」などのおかしなファイル名になってしまってる! という不具合が本日のお題。

環境は、Windows7(x86) 上の IE8 と、同 XPMode ( Windows XP SP3 ) 上の IE6。
ちなみに同じ Windows7(x86) 上の Firefox 3.6.4 では、ちゃんと日本語ファイル名でダウンロードダイアログが表示される。

IE のダウンロードダイアログにおける日本語ファイル名の取り扱いは過去苦労させられてきたが、
Internet Explorer でのダウンロード時、既定のファイル名の空白が "+" に化けてしまう
Internet Explorer 6 でのダウンロード時、既定のファイル名として日本語使うと16文字にカットされてしまう
またもや、再来か、という感じ。
まぁまぁ、と、ASP.NET MVC2 のソースコードをひもといてみる。
わかったのは、日本語ファイル名の場合、ASP.NET MVC2 の FileContentResult クラスでは、RFC2231 に基づいたエンコードを施して Content-Disposition 応答ヘッダを構築する、ということ。
ところがどっこい、IE は RFC2231 で規定されているエンコード方式を理解しないとのこと。
@takepara さんに教えて頂いた下記ページに明記されていた。
http://support.microsoft.com/kb/436616/ja
@takepara さん、いつもありがとうございます。
上記 KB を読む限り、最善は Shift-JIS で応答ヘッダをエンコードせよ、とのこと。
なるほど。
ただし、今回は実績のある方法で取り急ぎ済ませておかなければいけない背景があった。
また、web.config をいじって、一律、応答ヘッダのエンコード方式を Shift-JIS にしてしまうと、今度は IE 以外のブラウザが困る。
そこで、以前にもやっていた、ファイル名を Urlエンコードすること、プラス、若干の加工の戦法でいくことにした。
(上記KBに書かれているとおり、最善策ではないが )
FileContentResult クラスから派生した独自の MyFileContentResult クラスを作成。
詳細は端折るが、下記の要領で ExecuteResult メソッドをオーバーライドする。
public override void ExecuteResult(ControllerContext context)
{
// IE 以外では基底の処理に任せる(RFC2231)
if (context.HttpContext.Request.Browser.Browser != "IE")
base.ExecuteResult(context);
else
{
var fileName = this.FileDownloadName;
fileName = HttpUtility.UrlEncode(fileName).Replace("+", "%20");
var response = context.HttpContext.Response;
response.ContentType = this.ContentType;
response.AddHeader("content-disposition", "attachment; filename=" + fileName);
this.WriteFile(response);
}
この MyFileContentResult オブジェクトをアクションメソッドから返すことで、解決とした。
いずれ機会があれば、web.config の設定変更に依らず、ブラウザが IE だった場合に動的に Content-Disposition のエンコード方式を Shift-JIS とする実装を試してみるか。