C# RestSharp 库 - 加载大型"application/octect-stream"时报告进度



我知道这个问题已经多次提交,但是最后一个答案已经过时了,我想知道今天是否有解决方案吗?这不是功能请求。我宁愿寻找任何可以起作用的解决方法。

我在与我的API交谈的客户端上使用RestSharp。API用"应用程序/octect-stream"回复,最多需要几分钟才能下载。链接到GitHub代码。

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);
      });
}

我需要报告对我的UI的"响应"接收的进度,以建立一个进度栏或类似的东西。我已经知道收到预期的数据量(通过以前的API响应),我只需要知道在收到完整响应并解析的全部响应之前收到了多少个字节。

我不相信RestSharp当前提供"报告进度"类型的活动,对吗?我可以看到几种方法:

  1. 使用 client.downloaddata(请求).saveas(path); 。也许该文件是在下载时创建的。我可以阅读文件的大小以报告下载的进度。但是我的第一个印象是客户首先下载数据,然后保存文件。在这种情况下,这无济于事。
  2. 使用流来加载响应。定期评估流的大小,或每次缓冲尺寸延伸。
  3. 将响应类型从API更改为另一个(例如,在JSON中发送数据?)。
  4. 还有其他选项吗?

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

在执行eocuteasync仍在执行时,我可以访问"响应"的原始字节?我应该使用执行(没有Asyn)吗?我应该在常规更新时使用流和更新流的大小吗?

我设法获得了进度报告,但没有使用RestSharp。我在此处使用了基于Kievic的答案的System.net.httpclient。正如Kievic所强调的那样,这里的关键是 aclient.sendasync 返回一旦收到HTTP标头并读取了HTTP标头,但内容仍在加载。然后,内容在段循环中缓慢加载通过流。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.downloadedsize and this.progress 被分配一个新值,它们会触发一个可以被UI捕获的事件。

        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)));

最新更新