繁体   English   中英

等待异步文件上传完成,同时报告进度

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM