wpf 上传文件带进度条

在网上找了好久,才找到一位俄罗斯大神写的文章。

遇到超大文件的话还是会报异常。

 

服务端采用webapi

[Authorize]
[HttpPost]
public async Task<IActionResult> Post(IFormFile file)
{

var content = new MultipartFormDataContent();

var fileContent = new StreamContent(file.OpenReadStream());
fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(file.ContentType);

Stream stream = file.OpenReadStream();

return Ok();

}

客户端wpf

public async Task UploadAsync(Uri uri, Stream stream, IProgress<float> progress, CancellationToken cancelToken = default(CancellationToken))
        {
            if (uri == null) throw new ArgumentNullException(nameof(uri));
            if (stream == null) throw new ArgumentNullException(nameof(stream));
            if (progress == null) throw new ArgumentNullException(nameof(progress));

            // Название файла
            var fileName = System.IO.Path.GetFileName(((FileStream)stream).Name);

            // Подготавливаем контент потока
            var streamContent = new ProgressStreamContent(stream);
            streamContent.Headers.ContentType = new MediaTypeHeaderValue("text/plain");
            streamContent.ProgressChanged += (bytes, currBytes, totalBytes) 
                => progress.Report((float)currBytes / totalBytes * 100);

            // Данные на отправление
            var content = new MultipartFormDataContent();
            content.Add(streamContent, "file", fileName);

            try
            {
                using (var client = new HttpClient())
                {
                    client.DefaultRequestHeaders.Accept.Clear();
                    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
                    // Здесь скорее всего устанавливаем всякие заголовки
                    // ...

                    // Посылаем Post запрос
                    var response = await client.PostAsync(uri, content, cancelToken);

                    // Проверяем статус ответа
                    switch (response.StatusCode)
                    {
                        case HttpStatusCode.OK:
                            this.Close();
                            break;
                        default:
                            break;
                    /* Здесь проверяем статус ответа и предпринимаем действия */
                    }
                }
            }
            catch (HttpRequestException ex)
            {
                throw new Exception(ex.Message);
            }
        }
    public delegate void ProgressHandler(long bytes, long currentBytes, long totalBytes);

    class ProgressStreamContent : StreamContent
    {
        private const int DEFAULT_BUFFER_SIZE = 4096;

        public event ProgressHandler ProgressChanged = delegate { };

        private long currentBytes = 0;
        private long totalBytes = -1;


        public Stream InnerStream { get; }
        public int BufferSize { get; }

        public ProgressStreamContent(Stream innerStream, int bufferSize = DEFAULT_BUFFER_SIZE) :
            base(innerStream, bufferSize)
        {
            InnerStream = innerStream ?? throw new ArgumentNullException(nameof(innerStream));
            BufferSize = bufferSize > 0 ? bufferSize : throw new ArgumentOutOfRangeException(nameof(bufferSize));
        }

        private void ResetInnerStream()
        {
            if (InnerStream.Position != 0)
            {
                // Если внутренний поток нужно считать повторно, то этот внутренний поток должен поддерживать
                // возврат каретки(например FileStream), иначе внутренний поток не может быть считан повторно
                // в целевой поток(например NetworkStream)
                if (InnerStream.CanSeek)
                {
                    InnerStream.Position = 0;
                    currentBytes = 0;
                }
                else
                    throw new InvalidOperationException("The inner stream has already been read!");
            }
        }

        protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
        {
            if (stream == null) throw new ArgumentNullException(nameof(stream));

            // Сбрасываем состояние внутреннего потока
            ResetInnerStream();

            // Если общее количество байт еще не получено, то пытаемся получить
            // его из заголовков контента
            if (totalBytes == -1)
                totalBytes = Headers.ContentLength ?? -1;

            // Если общее количество байт еще не найдено, то пытаемся
            // вычислить его из потока
            if (totalBytes == -1 && TryComputeLength(out var computedLength))
                totalBytes = computedLength == 0 ? -1 : computedLength;

            // Если общее количество байт отрицательное значение, то
            // присваеваем ему -1, идентифицирующее о невалидном общем количестве байт
            totalBytes = Math.Max(-1, totalBytes);

            // Начинаем читать внутренний поток
            var buffer = new byte[BufferSize];
            var bytesRead = 0;
            while ((bytesRead = await InnerStream.ReadAsync(buffer, 0, buffer.Length)) != 0)
            {
                stream.Write(buffer, 0, bytesRead);
                currentBytes += bytesRead;
                Thread.Sleep(100);
                // Генерируем событие ProgressChanged, чтобы оповестить о текущем прогрессе считывания
                ProgressChanged(bytesRead, currentBytes, totalBytes);
            }
        }

        protected override bool TryComputeLength(out long length)
        {
            var result = base.TryComputeLength(out length);
            totalBytes = length;
            return result;
        }

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

            base.Dispose(disposing);
        }
    }

调用

await UploadAsync(new Uri(upUrl + apiName), stream, new Progress<float>((percent) =>
            {
                this.Pbupload.Dispatcher.Invoke(new Action(delegate
                {
                    Pbupload.Value = percent;
                }));
            }));

 

posted @ 2022-09-08 15:21  ccqin  阅读(249)  评论(0编辑  收藏  举报