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目前提供了“报告进度”类型的事件,对吧?我可以看到几种方法:
- 使用client.DownloadData(request).SaveAs(path);。也许该文件是在下载时创建的。我可以读取文件的大小来报告下载的进度。但我的第一印象是,客户端首先下载数据,然后保存文件。在那种情况下,这没有帮助。
- 使用流加载响应。定期评估流的大小,或每次缓冲区大小延伸。
- 将API的响应类型更改为另一个(例如,用JSON发送数据?)。
- 还有其他的选择吗?
您怎么看?任何人都设法报告上传的进度?
当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.DownloadedSize和this.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)));