by WebSurfer
2018年12月20日 11:27
MVC のアクションメソッドを使ってファイルをチャンク形式でエンコーディングしてブラウザにダウンロードする方法を書きます。
チャンク形式エンコーディングせず、普通に(Content-Length を設定して)ダウンロードする方法については先の記事「MVC でファイルのダウンロード」に書きましたのでそちらを見てください。
チャンク形式エンコーディングでダウンロードするには、その記事で紹介したようなヘルパーメソッド File は使えませんので別の手段を考えることになると思います。
結局は、(1) HttpResponse オブジェクトを取得、(2) それから OutputStream プロパティを使って出力ストリームを取得、(3) コンテンツをチャンクに分割して Write メソッドでストリームに書き込む、(4) Flush メソッドでクライアントに送信する、(5) 全チャンクを送信するまで (3) と (4) の操作を繰り返す・・・ということになると思います。
MVC のアクションメソッドでは Controller.Response プロパティで HttpResponse オブジェクトを取得できますので、それを使って上記 (1) ~ (5) の操作を行うことができます。
そのコードを以下に書いておきます。結局は Web Forms アプリの記事「チャンク形式でダウンロード」のコードとほぼ同じですが・・・
public void ChunkedDownload()
{
string folder = "~/Files/";
string filename = "Sig552T8.jpg";
string path = Server.MapPath(folder + filename);
FileInfo fileInfo = new FileInfo(path);
if (fileInfo.Exists)
{
int chunkSize = 10000;
Byte[] buffer = new Byte[chunkSize];
Response.Clear();
using (FileStream stream = System.IO.File.OpenRead(path))
{
long length = stream.Length;
Response.ContentType = "image/jpeg";
Response.AddHeader("Content-Disposition",
"attachment; filename=" + fileInfo.Name);
while (length > 0 && Response.IsClientConnected)
{
int lengthRead = stream.Read(buffer, 0, chunkSize);
Response.OutputStream.Write(buffer, 0, lengthRead);
Response.Flush();
length -= lengthRead;
}
}
}
}
アクションメソッドの戻り値は ActionResult である必要はなく void にできることに注意してください。
また、上のコードで最後を示す長さ 0 のチャンクも送信されます。(Fiddler で最後のバイト列が ... 0D 0A 30 0D 0A 0D 0A となっているのを確認しました)
もう一つ、MVC アプリでも HTTP ジェネリックハンドラ(.ashx ファイル)は使えますので、アクションメソッドを使わなくても、HTTP ジェネリックハンドラに同様な機能を実装することは可能です。