Неправильные обновления хода выполнения при загрузке через HTTP-запрос PUT с использованием HttpClient в .NET MAUIC#

Место общения программистов C#
Ответить
Anonymous
 Неправильные обновления хода выполнения при загрузке через HTTP-запрос PUT с использованием HttpClient в .NET MAUI

Сообщение Anonymous »

Я разрабатываю приложение .NET MAUI, в котором мне нужно загрузить файл с помощью запроса HTTP PUT, отслеживая при этом ход загрузки. Однако я сталкиваюсь со следующими проблемами с отчетами о ходе выполнения:
  • Обратный вызов прогресса запускается только один раз или немедленно сообщает о 100 % завершении — это происходит независимо от файла. размер или фактическую продолжительность загрузки.
  • Обновления хода выполнения происходят слишком быстро и не соответствуют процессу загрузки.
Что я пробовал
Я реализовал специальные HttpProgressMessageHandler и ProgressableStreamContent для отслеживания обновлений хода выполнения во время загрузки файлов. Ниже приведен соответствующий код:

Код: Выделить всё

public class HttpProgressMessageHandler(HttpMessageHandler innerHandler = null)
: DelegatingHandler(innerHandler ?? new HttpClientHandler())
{
public event EventHandler HttpSendProgress;

protected override async Task SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
if (request.Content == null)
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);

var originalContent = request.Content;
var contentLength = originalContent.Headers.ContentLength;

request.Content = new ProgressableStreamContent(
originalContent,
(bytesTransferred) =>
{
double percentage = 0;
if (contentLength > 0)
{
percentage = (double)bytesTransferred / contentLength.Value * 100.0;
}

HttpSendProgress?.Invoke(this, new HttpProgressEventArgs(percentage));
});

return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}

public class ProgressableStreamContent : HttpContent
{
private readonly HttpContent _originalContent;
private readonly Action _progressCallback;

public ProgressableStreamContent(HttpContent content, Action progressCallback)
{
_originalContent = content ?? throw new ArgumentNullException(nameof(content));
_progressCallback = progressCallback ?? throw new ArgumentNullException(nameof(progressCallback));

foreach (var header in _originalContent.Headers)
Headers.Add(header.Key, header.Value);
}

protected override bool TryComputeLength(out long length)
{
if (_originalContent.Headers.ContentLength.HasValue)
{
length = _originalContent.Headers.ContentLength.Value;
return true;
}

length = -1;
return false;
}

protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
const int bufferSize = 4096;
var buffer = new byte[bufferSize];
long totalBytes = 0;

await using var inputStream = await _originalContent.ReadAsStreamAsync().ConfigureAwait(false);
int bytesRead;
while ((bytesRead = await inputStream.ReadAsync(buffer, 0, bufferSize)) >  0)
{
await stream.WriteAsync(buffer, 0, bytesRead).ConfigureAwait(false);

totalBytes += bytesRead;
_progressCallback?.Invoke(totalBytes);
}

_progressCallback?.Invoke(totalBytes);
}

protected override void Dispose(bool disposing)
{
if (disposing)
{
_originalContent.Dispose();
}

base.Dispose(disposing);
}
}
Вот как я делаю запрос на загрузку:

Код: Выделить всё

private async Task UploadAsync(Uri uploadUri)
{
_cancellationToken.ThrowIfCancellationRequested();

HttpMessageHandler innerHandler = new HttpClientHandler();
var progressMsgHandler = new HttpProgressMessageHandler(innerHandler);
progressMsgHandler.InnerHandler = innerHandler;

progressMsgHandler.HttpSendProgress += (_, e) =>
{
UploadProgressChanged?.Invoke(this, (int)e.ProgressPercentage);
};

using var clientWithProgress = new HttpClient(progressMsgHandler);
clientWithProgress.DefaultRequestHeaders.TransferEncodingChunked = true;

await using var fileStream = _param.LogFileStream;
using var content = new StreamContent(fileStream);
using var response = await clientWithProgress.PutAsync(uploadUri, content, _cancellationToken);
response.EnsureSuccessStatusCode();
}
Дополнительные попытки
Я также попробовал настроить обработчик HTTP-клиента для iOS, чтобы настроить MaxInputInMemory для NSUrlSessionHandler.< /p>
Несмотря на все вышеперечисленные подходы, обратный вызов прогресса либо:
Срабатывает только один раз и немедленно сообщает 100% (с NSUrlSessionHandler).
Сообщает о прогрессе слишком быстро и не соответствует фактическому процессу загрузки (с помощью HttpClientHandler).
Как добиться надежности и точности отчеты о ходе загрузки файлов в .NET MAUI, особенно в iOS, где NSUrlSessionHandler, похоже, буферизует содержимое перед загрузкой? Есть ли какие-либо обходные пути или изменения, которые я могу внести, чтобы обеспечить постепенную загрузку и правильное обновление информации о ходе выполнения?

Подробнее здесь: https://stackoverflow.com/questions/793 ... httpclient
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»