HttpClient и PushStreamContent
Я использую PushStreamContent с моим REST API (ASP.NET Web API) и прекрасно работает. HttpClient может запросить ресурс и получает 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 web api?
Редактировать: это реализация WriteToStream (но я не использую файл с диска, это использовать поток памяти '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 будет буферизовать весь контент на самом клиенте, чтобы определить длину содержимого запроса, и именно по этой причине вы замечаете свой веб-интерфейс служба не вызывается сразу, когда вы пишете в поток...