0

i want realize a big file upload progress demo,but below code can't working normal. if remove the code "await Task.Delay(1)" in ProgressableStreamContent class,and id "mybar" element not refresh UI. if add "await Task.Delay(1)" ,it's work normal.can refresh UI,show progress. why? Has anyone encountered this problem? Can you help me with this? Thank you.

<p>
    <InputFile OnChange="@OnInputFileChange" />
</p>
<div>
    <p>File Size:@totalSize   @progressPercent % </p>
    @{
        var progressWidthStyle = progressPercent + "%";
    }
<div class="progress">
    <div id="mybar" class="progress-bar" role="progressbar" style="width:@progressWidthStyle" area-valuenow="@progressPercent" aria-minvalue="0" aria-maxvalue="100"></div>
</div>
</div>
  private CancellationTokenSource cancelation;
    public long totalSize = 0;
    public int progressPercent = 0;
    private string _fileName = "";
    private async Task OnInputFileChange(InputFileChangeEventArgs e)
    {
        IBrowserFile imageFile = e.File;
        totalSize = imageFile.Size;
        var buffer = new byte[totalSize];


        await imageFile.OpenReadStream(512000*1000).ReadAsync(buffer);
        var content = new MultipartFormDataContent { { new ByteArrayContent(buffer), "\"upload\"", e.File.Name } };

        var progressContent = new ProgressableStreamContent(content, 10240,
          (sent, total) =>
          {
              progressPercent = (int)(sent * 100 / total);
              Console.WriteLine("Uploading {0}%", progressPercent);
            
              StateHasChanged();
          });
        var repsone = await client.PostAsync("http://localhost:5000/Home/Upload", progressContent);
        var taskStr = await repsone.Content.ReadAsStringAsync();
        Console.WriteLine("taskStr=" + taskStr);
    }
  public class ProgressableStreamContent : HttpContent
    {
        /// <summary>
        /// Lets keep buffer of 20kb
        /// </summary>
        private HttpContent content;
        private int bufferSize;
        //private bool contentConsumed;
        private Action<long, long> progress;
        public ProgressableStreamContent(HttpContent content, int bufferSize, Action<long, long> progress)
        {
            if (content == null)
            {
                throw new ArgumentNullException("content");
            }
            if (bufferSize <= 0)
            {
                throw new ArgumentOutOfRangeException("bufferSize");
            }

            this.content = content;
            this.bufferSize = bufferSize;
            this.progress = progress;

            foreach (var h in content.Headers)
            {
                this.Headers.Add(h.Key, h.Value);
            }
        }

        protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
        {

            var buffer = new Byte[this.bufferSize];
            long size;
            TryComputeLength(out size);
            var uploaded = 0;


            using (var sinput = await content.ReadAsStreamAsync())
            {
                while (true)
                {
                    var length = sinput.Read(buffer, 0, buffer.Length);
                    if (length <= 0) break;

                    //downloader.Uploaded = uploaded += length;
                    uploaded += length;
                    progress?.Invoke(uploaded, size);
                    await Task.Delay(1);
                    //System.Diagnostics.Debug.WriteLine($"Bytes sent {uploaded} of {size}");
                
                    await stream.WriteAsync(buffer, 0, length);
                }
            }
            stream.Flush();

        }

        protected override bool TryComputeLength(out long length)
        {
            length = content.Headers.ContentLength.GetValueOrDefault();
            return true;
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                content.Dispose();
            }
            base.Dispose(disposing);
        }
    }
small pig
  • 19
  • 4
  • 2
    WebAssembly is running on a single thread, to change the progress, we have to use the `Task.Delay(1)` to change the flush again. Check this the following threads: [Blazor WebAssembly: How to get UI to update during long running, non-async process](https://stackoverflow.com/questions/60584294/) and [Blazor - Display wait or spinner on API call](https://stackoverflow.com/questions/56604886/) – Zhi Lv Nov 16 '20 at 10:41
  • how to vote for you with this question? – small pig Nov 17 '20 at 09:29

1 Answers1

0

It's not possible using the Blazor's HttpClient, because it uses the browser's fetch-API behind the scene and this API doesn't support streaming at the moment.

VahidN
  • 18,457
  • 8
  • 73
  • 117