非常に大きなファイル (>2GB) を WebAPI アプリケーション (.NET 4.5.2、Windows 2012R2 で実行) にアップロードしようとしています。
httpRuntime maxRequestLength プロパティを設定しても、2GB 未満のファイルでのみ機能するため、意味がありません。
現在、カスタム MultipartFormDataStreamProvider を使用してサーバー上のストリーム全体を読み取り、カスタム WebHostBufferPolicySelector を使用してバッファリングを既にオフにしています。
私が発見したのは、ASP.NET (または WebAPI) が、_disableMaxRequestLength というフィールドを持つ HttpBufferlessInputStream を内部的に使用していることです。この値を true に設定すると (リフレクション経由)、任意のサイズのファイルをストリーミングできます。
しかし、これらの内部をいじくり回すのは明らかに良い方法ではありません。
リクエストに使用されるHttpRequestクラスには、バッファレス入力ストリームを取得するmaxRequestLength を無効にできるオーバーロードがあります。
私の質問は、WebAPI で標準のオーバーロードではなくこのオーバーロードを使用するにはどうすればよいかということです。
デフォルトの HttpRequest クラスまたは HttpContext クラスを置き換える方法はありますか? それとも、すべてのものにリフレクションを使用する必要がありますか?
これは現在 maxRequestLength を無効にするために使用しているコードです:
private void DisableRequestLengthOnStream(HttpContent parent)
{
var streamContentProperty = parent.GetType().GetProperty("StreamContent", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (streamContentProperty == null) return;
var streamContent = streamContentProperty.GetValue(parent, null);
if (streamContent == null) return;
var contentProperty = typeof(StreamContent).GetField("content", BindingFlags.Instance | BindingFlags.NonPublic);
if (contentProperty == null) return;
var content = contentProperty.GetValue(streamContent);
if (content == null) return;
var requestLengthField = content.GetType().GetField("_disableMaxRequestLength", BindingFlags.Instance | BindingFlags.NonPublic);
if (requestLengthField == null) return;
requestLengthField.SetValue(content, true);
}
ベストアンサー1
はい、とても簡単な解決策を見つけました。もちろん、@JustinR からの回答は有効です。ただし、MIME 関連のすべてを処理できる MultipartFormDataStreamProvider を引き続き使用したいと考えました。
解決策は、正しいバッファレス入力ストリームを使用して新しい StreamContent インスタンスを作成し、元のコンテンツのヘッダーを入力するだけです。
var provider = new MultipartFormDataStreamProvider(path);
var content = new StreamContent(HttpContext.Current.Request.GetBufferlessInputStream(true));
foreach (var header in Request.Content.Headers)
{
content.Headers.TryAddWithoutValidation(header.Key, header.Value);
}
await content.ReadAsMultipartAsync(provider);