System.Net.Http.HttpClient是否会受到HttpWebRequest.AllowWriteStreamBuffering的影响?

时间:2013-04-16 12:36:35

标签: .net httpclient out-of-memory

我一直在尝试使用System.Net.Http.HttpClient来发布一个更大的文件(+ 1GB),但它会引发SystemOutOfMemory异常:

at System.Net.ScatterGatherBuffers.AllocateMemoryChunk(Int32 newSize)
at System.Net.ScatterGatherBuffers..ctor(Int64 totalSize)
at System.Net.ConnectStream.EnableWriteBuffering()
at System.Net.HttpWebRequest.SetRequestSubmitDone(ConnectStream submitStream)
at System.Net.Connection.CompleteStartRequest(Boolean onSubmitThread, HttpWebRequest request, TriState needReConnect)
at System.Net.Connection.SubmitRequest(HttpWebRequest request, Boolean forcedsubmit)
at System.Net.ServicePoint.SubmitRequest(HttpWebRequest request, String connName)
at System.Net.HttpWebRequest.SubmitRequest(ServicePoint servicePoint)
at System.Net.HttpWebRequest.BeginGetRequestStream(AsyncCallback callback, Object state)
at System.Net.Http.HttpClientHandler.StartGettingRequestStream(RequestState state)
at System.Net.Http.HttpClientHandler.PrepareAndStartContentUpload(RequestState state)

显然,HttpWebRequest出现类似问题,如此处所述:http://support.microsoft.com/kb/908573

有没有办法将基础网络请求的AllowWriteStreamBuffering设置为false?我找不到任何。

干杯,

4 个答案:

答案 0 :(得分:3)

为了节省其他感兴趣的时间,我正在回答我自己的问题。

经过几次测试后,异常似乎与问题中讨论的HttpWebRequest的问题相同。我使用Microsoft.AspNet.WebApi版本4.0.20710.0。

以下是两段相同的代码;前者在大文件上失败,而后者工作正常。

顺便说一下,尽管HttpClient的整体好处问题变得非常明显: - )


使用HttpClient

var clientRef = new System.Net.Http.HttpClient(
    new HttpClientHandler()
    {
        Credentials = new System.Net.NetworkCredential(MyUsername, MyPassword)
    });
clientRef.BaseAddress = new Uri(serverAddress);
clientRef.DefaultRequestHeaders.ExpectContinue = false;
clientRef.PostAsync(
    MyFavoriteURL,
    new System.Net.Http.StreamContent(inputStream)).ContinueWith(
        requestTask =>
        {
            HttpResponseMessage response = requestTask.Result;
            response.EnsureSuccessStatusCode();
        }, TaskContinuationOptions.LongRunning).Wait();

使用HttpWebRequest

// Preauthenticate
var req  = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(MyFavoriteURL);
req.Credentials = new System.Net.NetworkCredential(MyUsername, MyPassword);
req.Method = "POST";
req.PreAuthenticate = true;
req.Timeout = 10000;
using (var resp = (System.Net.HttpWebResponse)req.GetResponse())
{
     if (resp.StatusCode != System.Net.HttpStatusCode.Accepted && resp.StatusCode != System.Net.HttpStatusCode.OK)
     {
         throw new Exception("Authentication error");
     }
}

// Upload
req = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(MyFavoriteURL);
req.Credentials = new System.Net.NetworkCredential(MyUsername, MyPassword);
req.Method = "POST";
req.PreAuthenticate = true;
req.Timeout = 1200000;
req.ContentLength = inputStream.Length;
req.ContentType = "application/binary";
req.AllowWriteStreamBuffering = false;
req.Headers.ExpectContinue = false;
using (var reqStream = req.GetRequestStream())
{
    inputStream.CopyTo(reqStream);
}

using (var resp = (System.Net.HttpWebResponse)req.GetResponse())
{
    if (resp.StatusCode != System.Net.HttpStatusCode.Accepted && resp.StatusCode != System.Net.HttpStatusCode.OK)
    {
        throw new Exception("Error uploading document");
    }
}

答案 1 :(得分:0)

我也遇到了大文件上传的同样问题。添加我的发现,以便它可以帮助某人。

HttpClient根据以下条件确定是否进行缓冲,

if( HttpRequestMessage.Headers.TransferEncodingChunked == true ||     HttpRequestMessage.Content.Headers.ContentLength != null )
{
  //do streamed upload
}else
{
  //do buffered upload.
}

我已将PushedStreamContent用作HttpRequestMessage.Content,因为我的服务器每个请求最多接受150 MB。一旦我将TransferEncodingChunked设置为True,内存峰值就会减少。

答案 2 :(得分:0)

我认为你有一个重复的标题,你可以删除前一个

req.Headers.Add("ExpectContinue", "false");
...
req.Headers.ExpectContinue = false;

答案 3 :(得分:0)

帮助我发送大文件而不通过“继电器控制器”进行缓冲 我开始工作的场景是:
客户端网络应用程序(spa等) - > RelayController - >存储http数据流的最终内容控制器

        var request = new HttpRequestMessage()
        {

            RequestUri = new Uri("https://someurl/api/upload"),
            Method = HttpMethod.Post,
        };
        request.Headers.TransferEncodingChunked = true;
        request.Content = new StreamContent(Request.Body);

        await httpClient.SendAsync(request);`

花了很多时间让它上班,得到了Prakash P的领导,他发布了httpclient流媒体与缓冲逻辑。