バッファリングされていないファイルのアップロードを作成しようとして、System.Web.Http.WebHost.WebHostBufferPolicySelector を拡張し、この記事で説明されているように関数 UseBufferedInputStream() をオーバーライドしました: http://www.strathweb.com/2012/09/dealing -with-large-files-in-asp-net-web-api/ . ファイルがコントローラーに POST されると、トレース出力で、上書きされた関数 UseBufferedInputStream() が期待どおり確実に FALSE を返していることがわかります。ただし、診断ツールを使用すると、ファイルがアップロードされるにつれてメモリが増加することがわかります。
私のカスタム MediaTypeFormatter (FileMediaFormatter のようなもの: http://lonetechie.com/ ) で大量のメモリ使用量が発生しているようです。受信ファイルをインクリメンタルにディスクに書き込みたいのはこのフォーマッタですが、json を解析し、Content-Type:multipart/form-data アップロードで他の操作を行う必要もあります。したがって、私は HttpContent メソッド ReadAsMultiPartAsync() を使用していますが、これがメモリ増加の原因のようです。「待機」の前後にトレース出力を配置しましたが、タスクがブロックされている間、メモリ使用量がかなり急速に増加しているようです。
ReadAsMultiPartAsync() によって返されたパーツでファイルの内容を見つけたら、ファイルの内容をディスクに書き込むために Stream.CopyTo() を使用しています。これは期待どおりにディスクに書き込みますが、残念ながら、ソース ファイルはこの時点で既にメモリ内にあります。
何がうまくいかないのか考えている人はいますか?ReadAsMultiPartAsync() が投稿データ全体をバッファリングしているようです。それが本当なら、ファイルの内容を取得するために var fileStream = await fileContent.ReadAsStreamAsync() が必要なのはなぜですか? パーツをメモリに読み込まずに分割する別の方法はありますか? 私の MediaTypeFormatter のコードは次のようになります。
// save the stream so we can seek/read again later
Stream stream = await content.ReadAsStreamAsync();
var parts = await content.ReadAsMultipartAsync(); // <- memory usage grows rapidly
if (!content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
//
// pull data out of parts.Contents, process json, etc.
//
// find the file data in the multipart contents
var fileContent = parts.Contents.FirstOrDefault(
x => x.Headers.ContentDisposition.DispositionType.ToLower().Trim() == "form-data" &&
x.Headers.ContentDisposition.Name.ToLower().Trim() == "\"" + DATA_CONTENT_DISPOSITION_NAME_FILE_CONTENTS + "\"");
// write the file to disk
using (var fileStream = await fileContent.ReadAsStreamAsync())
{
using (FileStream toDisk = File.OpenWrite("myUploadedFile.bin"))
{
((Stream)fileStream).CopyTo(toDisk);
}
}