C#RestSharp Library - Report当加载一个大的“应用程序/ octect-stream”时的进度

问题描述:

我知道这个问题已经提交了多次,但最后的答案是过时的,我想知道现在有没有可用的解决方案?这不是功能请求。我宁愿寻找任何可行的解决方法。C#RestSharp Library - Report当加载一个大的“应用程序/ octect-stream”时的进度

我在与我的API交谈的客户端上使用RestSharp。该API回复“应用程序/ octect-stream”,可能需要几分钟的时间才能下载。链接到GitHub code here

public void Download() 
{ 
    if (NewerApp == null) return; 

     var client = new RestClient(ServerAddress); 
     var request = new RestRequest("/Apps/", Method.POST); 
     request.AddParameter("id", CurrentApp.EncryptedId()); 
     request.AddParameter("action", "download"); 

     var asyncHandle = client.ExecuteAsync<App>(request, response => { 
      HandleResponseToDownloadRequest(response); 
     }); 
} 

我需要向我的用户界面报告接收“响应”的进度,以建立一个进度条或类似的东西。我已经知道要接收的数据量(通过以前的API响应),我只需要知道在收到并解析完整响应之前接收了多少个字节。

我不相信RestSharp目前提供了“报告进度”类型的事件,对吧?我可以看到几种方法:

  1. 使用client.DownloadData(request).SaveAs(path);。也许该文件是在下载时创建的。我可以读取文件的大小来报告下载的进度。但我的第一印象是,客户端首先下载数据,然后保存文件。在那种情况下,这没有帮助。
  2. 使用流加载响应。定期评估流的大小,或每次缓冲区大小延伸。
  3. 将API的响应类型更改为另一个(例如,用JSON发送数据?)。
  4. 还有其他的选择吗?

您怎么看?任何人都设法报告上传的进度?

当ExecuteAsync仍在执行时,我可以访问RawBytes的'响应'吗?我应该使用Execute(没有Asyn)吗?我应该使用流和更新观看定期更新流的大小?

我设法得到一个进度报告,但没有使用RestSharp。我使用了基于kievic的回答here的System.Net.HttpClient。正如kievic强调的,这里的关键是aClient.SendAsync一旦收到HTTP头并被读取,但内容仍在加载。然后,内容通过while循环中的流缓慢加载。 RestSharp似乎并未启用此功能,或者我无法实现此功能。

public async Task DownloadAsync(Action<bool> callback) 
    { 
     if (NewerApp == null) return; 

     // Your original code. 
     HttpClientHandler aHandler = new HttpClientHandler(); 
     aHandler.ClientCertificateOptions = ClientCertificateOption.Automatic; 
     HttpClient aClient = new HttpClient(aHandler); 
     aClient.DefaultRequestHeaders.ExpectContinue = false; 
     HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Post, ServerAddress + "/Apps/"); 
     string content = "id=" + CurrentApp.EncryptedId() + "&action=download"; 
     message.Content = new StringContent(content); 
     HttpResponseMessage response = await aClient.SendAsync(message, 
      HttpCompletionOption.ResponseHeadersRead); // Important! ResponseHeadersRead. 

     // New code. 
     Stream stream = await response.Content.ReadAsStreamAsync(); 
     MemoryStream memStream = new MemoryStream(); 

     // Start reading the stream 
     var res = stream.CopyToAsync(memStream); 

     // While reading the stream 
     while (true) 
     { 
      // Report progress 
      this.DownloadedSize = memStream.Length; 
      this.Progress = 100.0 * (double)memStream.Length/(double)NewerApp.Filesize; 

      // Leave if no new data was read 
      if (res.IsCompleted) 
      { 
       // Report progress one last time 
       this.DownloadedSize = memStream.Length; 
       this.Progress = 100.0 * (double)memStream.Length/(double)NewerApp.Filesize; 

       break; 
      } 
     } 

     // Get the bytes from the memory stream 
     byte[] responseContent = new byte[memStream.Length]; 
     memStream.Position = 0; 
     memStream.Read(responseContent, 0, responseContent.Length); 

     // Function has ended - return whether the app was donwloaded 
     // properly and verified, or not 
     callback(HandleResponseToDownloadRequest(responseContent)); 
    } 

每次this.DownloadedSizethis.Progress被赋予了新的价值,他们开火可以通过用户界面被捕获的事件。

 private double progress = 0; 
    /// <summary> 
    /// Progress of the download of the App. From 0.0 (%) to 100.0 (%) 
    /// </summary> 
    public double Progress 
    { 
     get { return progress; } 
     set 
     { 
      // Max/Min 
      double val = value; 
      if (val > 100.0) val = 100; 
      else if (val < 0.0) val = 0.0; 

      // Assign value 
      if (progress != val) 
      { 
       progress = val; 
       OnProgressReport("Progress"); 
       OnPropertyChanged("Progress"); 
      } 
     } 
    } 

    public long downloadedSize = 0; 
    /// <summary> 
    /// Quantity of bytes downloaded of the app. 
    /// Note: there can be more bytes downloaded than advertized because 
    /// the quantity of advertize filesize is not encrypted while the 
    /// received bytes are encrypted. 
    /// TODO: advertize the size of the encrypted file. 
    /// </summary> 
    public long DownloadedSize 
    { 
     get 
     { 
      return downloadedSize; 
     } 
     set 
     { 
      if (downloadedSize != value) 
      { 
       downloadedSize = value; 
       OnDownloadedSizeReport("DownloadedSize"); 
      } 
     } 
    } 

/// <summary> 
    /// Fired when the progress of the download of the app file 
    /// has updated (more bytes received). 
    /// </summary> 
    public event PropertyChangedEventHandler ProgressReport; 
    protected void OnProgressReport(string name) 
    { 
     PropertyChangedEventHandler handler = ProgressReport; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 

    /// <summary> 
    /// Fired when the progress of the download of the app file 
    /// has updated (more bytes received). 
    /// </summary> 
    public event PropertyChangedEventHandler DownloadedSizeReport; 
    protected void OnDownloadedSizeReport(string name) 
    { 
     PropertyChangedEventHandler handler = DownloadedSizeReport; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(name)); 
     } 
    } 

我打电话DownloadAsync这样的:

// Start the download - await makes the execution of the method in background 
// so that UI can refresh and keep responsive. 
// downloaded: bool, true if file properly downloaded 
// Updater_AppDownloaded: function called once download has ended (failed or succeeded, either way) 
await System.Threading.Tasks.Task.Run(() => 
    Updater.DownloadAsync(downloaded =>  
     Updater_AppDownloaded(downloaded)));