2012-10-03 17 views
5

MVC4にファイルブラウザアプリケーションがあり、これを使用してコントローラから選択したファイルをダウンロードできます。ASP.NET MVC:FileResultから大量のデータを返す

現在、FileResultは、ファイルのストリームを他の応答ヘッダーとともに返します。これは小さいファイルでうまく動作しますが、大きいファイルはOutOfMemoryExceptionを生成します。

私がしたいのは、WebFormsのHttpReponse.TransmitFileに似た方法でメモリにバッファリングせずに、コントローラからファイルを送信することです。

これはどのように達成できますか?

答えて

2

はい、あなたはファイルをストリーミングするために、ウェブAPIを使用して、構成を説明する上記のリンクにAdditionalyこの記事でDealing with large files in ASP.NET Web API

+0

感謝次のエラーが発生しました: 'サービスタイプWebHostBufferPolicySelectorはサポートされていません。 –

+0

QuestionはWeb APIではなくMVCに関するものです –

0

を見てみることができ、あなたは「ストリーム」ファイルにTransmitFileを使用することができます。しかし、TransmitFileはいくつかのhttpクライアントでいくつか後方にあります。

これは、TransmitFileの代替として、ファイルをクライアントに「ストリームする」コードです。私は(あなたと同じOutOfMemoryを問題を持っている)のWriteFileをロールバックする一定の設定を持っていたことに注意してください:

private void RenderContent(string contentType,string fileName, bool inline); 

メソッドコード:

FileInfo fi = new FileInfo(fileName); 

Response.ClearHeaders(); 
Response.ClearContent(); 

Response.ContentType = contentType; 
Response.CacheControl = "No-cache"; 
Response.Cache.SetCacheability(System.Web.HttpCacheability.NoCache); 
Response.AddHeader("Content-Length", fi.Length.ToString()); 
Response.AddHeader("Content-Disposition", (inline ? "inline" : "attachment") + "; filename=\"" + fi.Name + "\""); 

if (cAppInfos.Constant["FallBackToWriteFile"] != null && cAppInfos.Constant["FallBackToWriteFile"] == "true") 
{ 
    Response.WriteFile(fileName); 
} 
else 
{ 
    int chunkSize = 8192; 
    byte[] buffer = new byte[chunkSize]; 
    int offset = 0; 
    int read = 0; 
    using (FileStream fs = File.Open(fileName, FileMode.Open, FileAccess.Read, FileShare.Read)) 
    { 
     while ((read = fs.Read(buffer, offset, chunkSize)) > 0) 
     { 
      if (!Response.IsClientConnected) 
       break; 

      Response.OutputStream.Write(buffer, 0, read); 
      Response.Flush(); 
     } 
    } 
} 

私は中にいくつかの問題を避けるために、このコードを使用しましたpdfファイルを古いacrobat readerプラグインにストリーミングする。インライン・パラメータの場合は、「false」を使用できます。

さらに、クライアントが切断された場合、Response.IsClientConnecter/Write/Flushのいずれかが例外をスローする可能性があるため、このコードをtry/catchで使用できます。

しかし、私はMVCを使用していないし、TransmitFileを使用していないかのように、このコードで同じ問題が発生する可能性があります。 Webページ要素にファイルを埋め込む場合(これはおそらくbase64のように)、これは解決策ではありません。

あなたの目標を達成するための他の方法が必要な場合は、要件に関する詳細情報をお知らせください。

+0

さらに、結果を "ストリームファイル"として提示する選択肢はコントローラには関係がなく、プレゼンテーション内で移動してResponseオブジェクトにアクセスできます。 コントローラは、プレゼンテーション層にストリーム... filestream/filenameを尋ねることができますか? – Echtelion

+0

あなたの「コントローラは単にプレゼンテーションレイヤーにストリームを尋ねるかもしれません...」というコメントに応じて、同じ方法でストリームを配信する必要があるため、別の場所に同じ問題を導入するだけですか? –

+0

私はMVCのエキスパートではありませんが、問題を解決できる場所(つまり、レスポンスオブジェクトにアクセスできる場所)で問題を移動することをお勧めします – Echtelion

8

ファイルの結果を返す前に応答バッファを無効にすることができます。私が取得 `ライン私のGlobal.asax.csファイルに、;` GlobalConfiguration.Configuration.Services.Replace(typeof演算(WebHostBufferPolicySelector)、新しいNoBufferPolicySelectorを())追加した後、リンクを使用して -

Response.BufferOutput = false; 
return File(fileStream, contentType); 
+1

これは私にとっては唯一の解決策です、ありがとう! –

+1

本当に大きなファイル(2GB +)の場合は、 'HttpCompletionOption.ResponseHeadersRead'を設定して、'設定された最大バッファサイズよりも多くのバイトをバッファに書き込めません:2147483647.'例外を防ぐ必要があることに注意してください。 –

関連する問題