Я пытаюсь получить прогресс API вместе с ответом. ResponseHeadersRead
отлично работает, чтобы получить прогресс, но я не могу понять, почему он не возвращает ответ.
Скачать часть
public async Task StartDownload()
{
_httpClient = new HttpClient { Timeout = TimeSpan.FromDays(1), };
using (var response = await _httpClient.GetAsync(_downloadUrl, HttpCompletionOption.ResponseHeadersRead))
{
await DownloadFileFromHttpResponseMessage(response);
string strResp = await response.Content.ReadAsStringAsync();
Debug.WriteLine(strResp); // Doesn't print anything
}
}
Часть потока чтения
private async Task DownloadFileFromHttpResponseMessage(HttpResponseMessage response)
{
response.EnsureSuccessStatusCode();
var totalBytes = response.Content.Headers.ContentLength;
using (var contentStream = await response.Content.ReadAsStreamAsync())
{
await ProcessContentStream(totalBytes, contentStream);
}
}
Код на самом деле от другой ответ.
Я просто не получаю ответа. Если я использую ResponseContentRead
, я получаю ответ, но это противоречит цели прогресса.
РЕДАКТИРОВАТЬ
Код ProcessContentStream — эта часть читает ответ по мере его поступления и публикует прогресс в TriggerProgressChanged
private async Task ProcessContentStream(long? totalDownloadSize, Stream contentStream)
{
var totalBytesRead = 0L;
var readCount = 0L;
var buffer = new byte[8192];
var isMoreToRead = true;
using (var fileStream = new FileStream(DestinationFilePath, FileMode.Create, FileAccess.Write, FileShare.None, 8192, true))
{
do
{
var bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
isMoreToRead = false;
//TriggerProgressChanged(totalDownloadSize, totalBytesRead);
continue;
}
await fileStream.WriteAsync(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
readCount += 1;
if (readCount % 100 == 0)
{
//TriggerProgressChanged(totalDownloadSize, totalBytesRead);
}
}
while (isMoreToRead);
}
}
Опубликовать прогресс
private void TriggerProgressChanged(long? totalDownloadSize, long totalBytesRead)
{
if (ProgressChanged == null)
return;
double? progressPercentage = null;
if (totalDownloadSize.HasValue)
progressPercentage = Math.Round((double)totalBytesRead / totalDownloadSize.Value * 100, 2);
ProgressChanged(totalDownloadSize, totalBytesRead, progressPercentage);
}
ProgressChanged
— это метод делегата.
Ну, я должен читать поток, чтобы получить прогресс. Как только это будет сделано, мне нужно передать ответ или прочитать его как строку. Что делать в этом случае?
Можете ли вы объяснить, что вы подразумеваете под «получить прогресс»? Что делает ProcessContentStream
?
C# не всегда делает процесс загрузки доступным для пользователя. Поэтому вам нужно написать свой собственный код загрузки, захватив поток. Мне также нужно показать пользователю ход загрузки, если файл большой.
Затем вам нужно вернуть ответ из вашего пользовательского метода загрузки.
См. stackoverflow.com/a/43169927/3480088 для кода ProcessContentStream
.
Итак, я нашел решение. Мне нужно было прочитать файл, в который я записал байты, так как он приходил с StreamReader
. Чтение файла с StreamReader
было объяснено здесь.
private async Task DownloadFileFromHttpResponseMessage(HttpResponseMessage response)
{
response.EnsureSuccessStatusCode();
var totalBytes = response.Content.Headers.ContentLength;
using (var contentStream = await response.Content.ReadAsStreamAsync())
{
await ProcessContentStream(totalBytes, contentStream);
// Added code
char[] buffer;
using (StreamReader sr = new StreamReader(DestinationFilePath))
{
buffer = new char[(int)sr.BaseStream.Length];
await sr.ReadAsync(buffer, 0, (int)sr.BaseStream.Length);
}
Debug.WriteLine(new string(buffer)); // Now it prints the response
}
}
Не могли бы вы добавить код метода ProcessContentStream
и код, в котором вы назначаете DestinationFilePath
, потому что сейчас похоже, что вы обрабатываете поток из ответа, но затем вы читаете из файловой системы, и это вводит в заблуждение, принимая во внимание вопрос.
Это будет долго, но ладно. Сделаю это.
Вы используете StreamRader.ReadAsync
неправильно: метод может вернуть меньше символов, чем запрошено, поэтому вам нужно использовать цикл, но лучше просто использовать ReadToEnd
в String
напрямую. Кроме того, если ответ представляет собой двоичные данные, то этот код очень неверен, потому что char
в C#/.NET — это 16-битное значение, а не byte
. С# это не С.
DownloadFileFromHttpResponseMessage
? Вы пытаетесь прочитать один и тот же контент дважды. Если вы дочитаете ответ сReadAsStreamAsync
до конца, что еще вы ожидаете найти, позвонивReadAsStringAsync
? Я бы ничего не ожидал.