HttpClient и PushStreamContent
Я использую PushStreamContent с моим REST API (ASP.NET Web API) и отлично работает. HttpClient может запросить ressource и получает HTTP-ответ до того, как полный запрос будет обработан сервером (сервер все еще записывает в push-поток).
как HttpClient вы должны сделать одну маленькую вещь: использовать HttpCompletionOption.ResponseHeadersRead.
Теперь мой вопрос: Можно ли к этому другим путем? Из HttpClient - > загрузка данных через push-поток в веб-api?
я реализовал его, как показано ниже, но веб-api получает запрос не раньше, чем клиент закроет поток.
var asyncStream = new AsyncStream(fs);
PushStreamContent streamContent = new PushStreamContent(asyncStream.WriteToStream);
content.Add(streamContent);
HttpResponseMessage response = await c.SendAsync(new HttpRequestMessage(new HttpMethod("POST"), "http://localhost/...") { Content = content }, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
AsyncStream-это мой класс с делегатом:
public async void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
Это необходимо для Push-Stream.
возможно ли это как-то? HttpClient не отправляет запрос в веб-api, пока последние байты не будут записаны в поток...
что я должен сделать? Проблема на стороне клиента или возможно, на сервере / asp.net веб-api-сторона?
изменить: Это имплементация WriteToStream (но я не использую файл с диска, использую memorystream 'myMemoryStream' (передается в конструкторе):
public void WriteToStream(Stream outputStream, HttpContent content, TransportContext context)
{
try
{
var buffer = new byte[4096];
using (var stream = myMemoryStream)
{
var bytesRead = 1;
while (bytesRead > 0)
{
bytesRead = video.Read(buffer, 0, buffer.Length);
outputStream.Write(buffer, 0, bytesRead);
}
}
}
catch (HttpException ex)
{
return;
}
finally
{
outputStream.Close();
}
}
может быть, мне нужно что-то сделать с содержимым HttpContent, контекстом TransportContext ?
2 ответов
Я нашел решение своей проблемы:
Я хочу установить: httpWebRequest.AllowReadStreamBuffering = false;
HttpClient 4.0 выполняет буферизацию по умолчанию, и вы не можете получить доступ к свойству AllowReadStreamBuffering, поэтому вам нужно использовать HttpWebRequest напрямую. (Или вы можете использовать HttpClinet 4.5, есть поведение по умолчанию "потоковое") см.:http://www.strathweb.com/2012/09/dealing-with-large-files-in-asp-net-web-api/ 6. С помощью С помощью HttpClient)
второй проблемой был fiddler: Fiddler в настоящее время поддерживает только потоковую передачу ответов, а не запросов (Fiddler делает поведение HttpWebRequest/HttpClient неожиданным)
решение, которое сработало для меня:
HttpWebRequest httpWebRequest = HttpWebRequest.Create(...)
httpWebRequest.Method = "POST";
httpWebRequest.Headers["Authorization"] = "Basic " + ...;
httpWebRequest.PreAuthenticate = true;
httpWebRequest.AllowWriteStreamBuffering = false;
httpWebRequest.AllowReadStreamBuffering = false;
httpWebRequest.ContentType = "application/octet-stream";
Stream st = httpWebRequest.GetRequestStream();
st.Write(b, 0, b.Length);
st.Write(b, 0, b.Length);
//...
Task<WebResponse> response = httpWebRequest.GetResponseAsync();
var x = response.Result;
Stream resultStream = x.GetResponseStream();
//... read result-stream ...
обязательно сделайте requestMessage.Headers.TransferEncodingChunked = true;
на вашем сообщении запроса...причина в том, что если вы не установите это, HttpClient будет буферизировать весь контент на самом клиенте, чтобы выяснить длину контента запроса, и это причина, по которой вы замечаете, что ваша служба веб-api не вызывается сразу, когда вы пишете в поток...