web-dev-qa-db-ja.com

ASP.NETでファイルをストリーミングする最良の方法

ASP.NETを使用してファイルをストリーミングする最良の方法は何ですか?

これにはさまざまなメソッドがあるようですが、現在、ファイルをブラウザーに直接送信するhttpハンドラー内で Response.TransmitFile() メソッドを使用しています。これは、FLVをウェブルートの外部から埋め込みFlashビデオプレーヤーに送信するなど、さまざまな目的で使用されます。

ただし、これは信頼できる方法のようには思えません。特に、Internet Explorer(7)で奇妙な問題があり、1つまたは2つのビデオを表示した後にブラウザーがハングします。リンクなどをクリックしても効果はありません。サイトで再び機能するようにする唯一の方法は、ブラウザーを閉じて再度開くことです。

これは他のブラウザでも発生しますが、頻度ははるかに低くなります。いくつかの基本的なテストに基づいて、これはファイルのストリーミング方法に関係していると思います...おそらく接続が適切に閉じられていないか、またはそれらの線に沿った何かです。

いくつかのことを試しましたが、次の方法でうまくいくことがわかりました。

Response.WriteFile(path);
Response.Flush();
Response.Close();
Response.End();

これにより、上記の問題が回避され、ビデオを表示してもInternet Explorerがハングしなくなりました。

ただし、私の理解では Response.WriteFile() は最初にファイルをメモリにロードし、ストリーミングされるファイルの一部が非常に大きくなる可能性があることを考えると、これは理想的な解決策ではないようです。

他の開発者がASP.NETで大きなファイルをストリーミングする方法、特にFLVビデオファイルをストリーミングする方法に興味があります。

34
Mun

「aspx」パイプライン以外のものを使用します。特に、実行ハンドラー(ashx、またはconfigを介してマップされる)を作成します。これはminimumを実行し、チャンクで応答に書き込むだけです。ハンドラーは通常どおりquery-string/formからの入力を受け入れ、ストリーミングするオブジェクトを見つけ、データをストリーミングします(ループ内の適度なサイズのローカルバッファーを使用)。以下に示す簡単な(不完全な)例:

public void ProcessRequest(HttpContext context) {
    // read input etx
    context.Response.Buffer = false;
    context.Response.ContentType = "text/plain";
    string path = @"c:\somefile.txt";
    FileInfo file = new FileInfo(path);
    int len = (int)file.Length, bytes;
    context.Response.AppendHeader("content-length", len.ToString());
    byte[] buffer = new byte[1024];
    Stream outStream = context.Response.OutputStream;
    using(Stream stream = File.OpenRead(path)) {
        while (len > 0 && (bytes =
            stream.Read(buffer, 0, buffer.Length)) > 0)
        {
            outStream.Write(buffer, 0, bytes);
            len -= bytes;
        }
    }
}
51
Marc Gravell

次の記事をご覧ください ASP.NETでの大容量ファイルのダウンロードの追跡と再開 これは、ストリームを開いてすべてのビットを取り出すだけではなく、より詳細な情報を提供します。

Httpプロトコルは、範囲バイト要求と再開可能なダウンロードをサポートし、多くのストリーミングクライアント(ビデオプレーヤーやAdobe pdfなど)は、これらをチャンクして帯域幅を節約し、ユーザーに優れたエクスペリエンスを提供しようとします。

ささいなことではありませんが、それはよく費やされた時間です。

10
Robert Paulson

ファイルをストリームとして開いてから、Response.OutputStream.Write()を使用してみてください。例えば:

編集:悪いのですが、書き込みがバイトバッファをとることを忘れていました。修繕

byte [] buffer = new byte[1<<16] // 64kb
int bytesRead = 0;
using(var file = File.OpenRead(path))
{
   while((bytesRead = file.Read(buffer, 0, buffer.Length)) != 0)
   {
        Response.OutputStream.Write(buffer, 0, bytesRead);
   }
}
Response.Flush();
Response.Close();
Response.End();

編集2:これを試しましたか?うまくいくはずです。

8
Randolpho

さまざまな回答に投稿されたコードを含むさまざまな組み合わせを試した後、TransmitFileを呼び出す前にResponse.Buffer = trueを設定するように思われ、WebアプリケーションはInternet Explorerではるかに応答しやすくなりました。

この特定のケースでは、SWF拡張機能もASP.NETにマップされており、Webアプリケーションでカスタムハンドラーを使用してディスクからファイルを読み取り、Response.TransmitFile()を使用してブラウザーに送信しています。 SWFでもあるビデオファイルを再生するためのフラッシュベースのビデオプレーヤーがあり、このアクティビティのすべてをバッファリングせずにハンドラーを通過させると、IEで奇妙なことが発生する可能性があります。

3
Mun