web-dev-qa-db-ja.com

ASP.NET MVCへの大きなファイルのアップロードのストリーミング

私が取り組んでいるアプリケーションの場合、ユーザーが私たちのWebサイト経由で非常に大きなファイル(つまり、数ギガバイト)をアップロードできるようにする必要があります。残念ながら、ASP.NET MVCは、サービスを開始する前に、リクエスト全体をRAMにロードしているように見えます。このようなアプリケーションには必ずしも理想的ではありません。特に、以下:

if (request.Method == "POST")
{
    request.ContentLength = clientRequest.InputStream.Length;
    var rgbBody = new byte[32768];

    using (var requestStream = request.GetRequestStream())
    {
        int cbRead;
        while ((cbRead = clientRequest.InputStream.Read(rgbBody, 0, rgbBody.Length)) > 0)
        {
            fileStream.Write(rgbBody, 0, cbRead);
        }
    }
}

rAMへのバッファの考え方を回避できません。この動作を回避する簡単な方法はありますか?

59

私の最初のコードは基本的に正しいことがわかりました。必要な唯一の変更は変更することでした

request.ContentLength = clientRequest.InputStream.Length;

request.ContentLength = clientRequest.ContentLength;

前者はコンテンツ全体の長さを決定するためにリクエスト全体でストリーミングします。後者は単にContent-Lengthヘッダーをチェックするだけで、ヘッダーが完全に送信されている必要があります。これにより、IISでリクエストのストリーミングをほぼ即座に開始できるようになり、元の問題が完全に解消されます。

25

もちろん、これを行うことができます。 HttpWebRequestおよびIHttpHandlerを使用したRESTfulファイルのアップロード を参照してください。私はこの方法を数年間使用しており、少なくとも数ギガバイトのファイルでテストされたサイトを持っています。基本的に、独自のIHttpHandlerを作成します。これは、思ったより簡単です。

簡単に言えば、IHttpHandlerインターフェイスを実装するクラスを作成します。つまり、IsReusableプロパティとProcessRequestメソッドをサポートする必要があります。その上で、web.configに小さな変更があり、魅力のように機能します。リクエストのライフサイクルのこの段階では、アップロードされるファイル全体がメモリに読み込まれないため、メモリ不足の問題を適切に回避します。

Web.configでは、

<httpHandlers>
 <add verb="*" path="DocumentUploadService.upl" validate="false" type="TestUploadService.FileUploadHandler, TestUploadService"/>
</httpHandlers>

参照されているファイルDocumentUploadService.uplは実際には存在しません。これは、要求が標準ハンドラーによってインターセプトされないように、代替の拡張機能を提供するためのものです。ファイルアップロードフォームにそのパスを指定すると、FileUploadHandlerクラスが起動し、実際にファイルを受け取ります。

更新:実際、私が使用するコードはその記事とは異なり、機能する理由につまずいたと思います。私は HttpPostedFile クラスを使用します。ここで "ファイルはMIME multipart/form-data形式でアップロードされます。デフォルトでは、フォームフィールドとアップロードされたファイルを含むすべてのリクエストが256 KBは、サーバーのメモリに保持されるのではなく、ディスクにバッファーされます。 "

if (context.Request.Files.Count > 0)
{
    string tempFile = context.Request.PhysicalApplicationPath;
    for(int i = 0; i < context.Request.Files.Count; i++)
    {
        HttpPostedFile uploadFile = context.Request.Files[i];
        if (uploadFile.ContentLength > 0)
        {
            uploadFile.SaveAs(string.Format("{0}{1}{2}",
              tempFile,"Upload\\", uploadFile.FileName));
        }
    }
}
17
RedFilter