- Обратный вызов прогресса запускается только один раз или немедленно сообщает о 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
Мобильная версия