![](/img/trans.png)
[英]Download & extract zip file using Async / Await with progress reporting
[英]Wait for Async file upload to complete while reporting progress
我正在使用WebClient
异步上传文件。 我想等待上传完成,因为之后我需要执行相关操作。
据我了解,最好的选择是使所有代码异步,但这意味着将许多同步代码转换为异步代码。
现在,文件上传正在异步运行并报告进度。
但是,等待上载完成不起作用。
这是从Stephen Cleary的这篇文章 (“垂直分区”部分,图6)中获得的启发。 最大的区别是文件上传的返回类型为void,因此我将其包装在任务中。
我使用带有Microsoft.Bcl.Async
Nuget包的.NET Framework 4.0。
现在,它已在控制台应用程序中使用,但将来也可能会从Winforms应用程序中调用。
static void Main(string[] args)
{
var uri = new Uri("https://somefileuploadurl.com");
string file = @"C:\file.zip";
var watch = Stopwatch.StartNew();
var fileUploader = new FileUploader();
fileUploader.UploadFile(uri, file);
watch.Stop();
Console.WriteLine($"Finished in {watch.ElapsedMilliseconds} ms");
Console.ReadLine();
}
public class FileUploader
{
public void UploadFile(Uri uri, string file)
{
UploadFileAsync(uri, file).GetAwaiter().GetResult();
}
public async Task UploadFileAsync(Uri uri, string file)
{
using (var client = new WebClient())
{
client.UploadProgressChanged += UploadProgressChanged;
await Task.Factory.StartNew(() => client.UploadFileAsync(uri, "PUT", file))
.ConfigureAwait(false);
}
}
private void UploadProgressChanged(object sender, UploadProgressChangedEventArgs e)
{
Console.WriteLine($"Progress: {e.ProgressPercentage}%");
}
}
当前控制台输出:
在100毫秒内完成
进展:1%
进展:2%
进展:3%
..
进度:100%
所需的输出:
进展:1%
进展:2%
进展:3%
..
进度:100%
在[actualTime]毫秒内完成
我究竟做错了什么?
client.UploadFileAsync()
调用仅开始上传,但在完成之前返回。 因此,您将其包装的任务几乎立即完成。
您应该注册到UploadFileCompletedEvent
并使用TaskCompletionSource
指示上传完成的时间:
public async Task UploadFileAsync(Uri uri, string file)
{
using (var client = new WebClient())
{
TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
client.UploadProgressChanged += UploadProgressChanged;
// this sets the task to completed when the upload finished
client.UploadFileCompleted += (sender, e) => tcs.SetResult(0);
client.UploadFileAsync(uri, "PUT", file);
await tcs.Task.ConfigureAwait(false);
}
}
您甚至可以通过在事件处理程序中评估UploadFileCompletedEventArgs
并返回实际结果来进行一些增强:
// return the byte[] result
public async Task<byte[]> UploadFileAsync(Uri uri, string file)
{
using (var client = new WebClient())
{
// use correct result type for taskcompletionsource
TaskCompletionSource<byte[]> tcs = new TaskCompletionSource<byte[]>();
client.UploadProgressChanged += UploadProgressChanged;
client.UploadFileCompleted += (sender, e) =>
{
if (e.Cancelled) // the upload has been cancelled
tcs.SetCancelled();
else if (e.Error != null)
tcs.SetException(e.Error); // or faulted with an exception
else
tcs.SetResult(e.Result); // or finished and returned a byte[]
}
client.UploadFileAsync(uri, "PUT", file);
await tcs.Task.ConfigureAwait(false);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.