How can I calculate progress with HttpClient PostAsync?

后端 未结 2 930
春和景丽
春和景丽 2020-12-17 04:15

In my Windows Store App (c#) I need to upload MultipartFormDataContent (some strings content and some files) to server and get a huge file at response. The prob

相关标签:
2条回答
  • 2020-12-17 04:53

    I faced same issue. I fixed it by implementing custom HttpContent. I use this object to track percentage of upload progress, you can add an event to and listen it. You should customize SerializeToStreamAsync method.

    internal class ProgressableStreamContent : HttpContent
    {
        private const int defaultBufferSize = 4096;
    
        private Stream content;
        private int bufferSize;
        private bool contentConsumed;
        private Download downloader;
    
        public ProgressableStreamContent(Stream content, Download downloader) : this(content, defaultBufferSize, downloader) {}
    
        public ProgressableStreamContent(Stream content, int bufferSize, Download downloader)
        {
            if(content == null)
            {
                throw new ArgumentNullException("content");
            }
            if(bufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException("bufferSize");
            }
    
            this.content = content;
            this.bufferSize = bufferSize;
            this.downloader = downloader;
        }
    
        protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
        {
            Contract.Assert(stream != null);
    
            PrepareContent();
    
            return Task.Run(() =>
            {
                var buffer = new Byte[this.bufferSize];
                var size = content.Length;
                var uploaded = 0;
    
                downloader.ChangeState(DownloadState.PendingUpload);
    
                using(content) while(true)
                {
                    var length = content.Read(buffer, 0, buffer.Length);
                    if(length <= 0) break;
    
                    downloader.Uploaded = uploaded += length;
    
                    stream.Write(buffer, 0, length);
    
                    downloader.ChangeState(DownloadState.Uploading);
                }
    
                downloader.ChangeState(DownloadState.PendingResponse);
            });
        }
    
        protected override bool TryComputeLength(out long length)
        {
            length = content.Length;
            return true;
        }
    
        protected override void Dispose(bool disposing)
        {
            if(disposing)
            {
                content.Dispose();
            }
            base.Dispose(disposing);
        }
    
    
        private void PrepareContent()
        {
            if(contentConsumed)
            {
                // If the content needs to be written to a target stream a 2nd time, then the stream must support
                // seeking (e.g. a FileStream), otherwise the stream can't be copied a second time to a target 
                // stream (e.g. a NetworkStream).
                if(content.CanSeek)
                {
                    content.Position = 0;
                }
                else
                {
                    throw new InvalidOperationException("SR.net_http_content_stream_already_read");
                }
            }
    
            contentConsumed = true;
        }
    }
    

    Just for reference:

    public interface IDownload
    {
        event EventHandler<DownloadStateEventArgs> StateChanged;
        event EventHandler<DownloadStateEventArgs> Completed;
    
        DownloadState State { get; }
        Guid Id { get; }
        string Uri { get; }
        long Filesize { get; }
        long Downloaded { get; }
    
        Task DownloadAsync();
    }
    
    0 讨论(0)
  • 2020-12-17 04:56

    The WebAPI Client nuget has some classes for doing this. Take a look at the ProgressMessageHandler. It is a PCL library so it should run fine for a Windows Store App.

    0 讨论(0)
提交回复
热议问题