下载不影响UI的文件

时间:2014-03-10 07:02:14

标签: c# windows-8 download windows-8.1 dotnet-httpclient

我们目前正在使用HttpClient下载文件,因为我们的后端需要证书。

我有一个控件 - FileRow,这是一个带有code-behind个文件下载方法的UI元素,如下所示:

    if (FileIsDownloaded == false)
    {
        await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, () =>
        {
            DataManager.Instance.DownloadFile(this);
        });
    }
    if (ThumbnailIsDownloaded == false)
    {
        await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Low, () =>
        {
            DataManager.Instance.DownloadThumbnail(this);
        });
    }

下载单项是好的但是当我点击全部下载(约50项)时,整个UI开始冻结。

正如您所看到的,我试图给予请求低优先级 - 但结果仍然相同。

常见问题的答案:

1)是的,文件应该一次全部下载,而不是一个接一个地下载 2)DataManager.Instance.DownloadThumbnail(this) - 我这样做是为了对当前控制进行参考,以便我可以在进度条中报告进度。

有什么建议吗?

修改

下载如下:

public async void DownloadFile(FileRow fileRow)
{
    //Lot of checking for if file exist, if version is the same
    string LocalFilename = await DownloadManager.DownloadFile(fileRow.MyFile.file.id, fileRow.MyFile.file.version, fileRow.MyFile.file.filename,fileRow);
    // next is just using the filename string
}

最后我的下载:

public static async Task<string> DownloadFileOfCustomerAssetRow(int? id, int? version, string filename, FileRow fileRow)
    {
        try
        {
            HttpClientHandler aHandler = new HttpClientHandler();
            aHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;
            HttpClient aClient = new HttpClient(aHandler);
            customerAssetRow.CurrentFileDownload = aClient;
            aClient.DefaultRequestHeaders.ExpectContinue = false;
            HttpResponseMessage response = await aClient.GetAsync(WebServices.BackendStartUrl + "getFileData?id=" + id + "&version=" + version, HttpCompletionOption.ResponseHeadersRead);
            var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, Windows.Storage.CreationCollisionOption.GenerateUniqueName);
            fileRow.FileName = file.Name;
            using (var fs = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite))
            {
                Stream stream = await response.Content.ReadAsStreamAsync();
                IInputStream inputStream = stream.AsInputStream();
                ulong totalBytesRead = 0;
                while (true)
                {
                    IBuffer buffer = new Windows.Storage.Streams.Buffer(1024);
                    buffer = await inputStream.ReadAsync(
                        buffer,
                        buffer.Capacity,
                        InputStreamOptions.None);
                    if (buffer.Length == 0)
                    {
                        break;
                    }
                    totalBytesRead += buffer.Length;
                    fileRow.Progress.Value = fileRow.Progress.Value + 1024;
                    await fs.WriteAsync(buffer);
                }
                inputStream.Dispose();
            }
            fileRow.Progress.Visibility = Visibility.Collapsed;
            return file.Name;
        }
        catch (Exception e)
        {
            ErrorReporter.ReportError("Error in DownloadManager.cs in function DownloadFile.", e);
            return "";
        }
    }

1 个答案:

答案 0 :(得分:0)

您的async方法延续可能会过多地中断UI线程。尝试通过介绍DownloadFileOfCustomerAssetRow报告者,在背景逻辑(FileRow)和用户界面(IProgress<T>)之间建立更强的分离。然后确保背景逻辑中的每个await都有ConfigureAwait(false)

public static async Task<string> DownloadFileOfCustomerAssetRow(int? id, int? version, string filename, IProgress<int> progress)
{
    HttpClientHandler aHandler = new HttpClientHandler();
    aHandler.ClientCertificateOptions = ClientCertificateOption.Automatic;
    HttpClient aClient = new HttpClient(aHandler);
    customerAssetRow.CurrentFileDownload = aClient;
    aClient.DefaultRequestHeaders.ExpectContinue = false;
    HttpResponseMessage response = await aClient.GetAsync(WebServices.BackendStartUrl + "getFileData?id=" + id + "&version=" + version, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);
    var file = await ApplicationData.Current.LocalFolder.CreateFileAsync(filename, Windows.Storage.CreationCollisionOption.GenerateUniqueName).ConfigureAwait(false);
    fileRow.FileName = file.Name;
    using (var fs = await file.OpenAsync(Windows.Storage.FileAccessMode.ReadWrite).ConfigureAwait(false))
    {
        Stream stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
        IInputStream inputStream = stream.AsInputStream();
        ulong totalBytesRead = 0;
        while (true)
        {
            IBuffer buffer = new Windows.Storage.Streams.Buffer(1024);
            buffer = await inputStream.ReadAsync(
                buffer,
                buffer.Capacity,
                InputStreamOptions.None).ConfigureAwait(false);
            if (buffer.Length == 0)
            {
                break;
            }
            totalBytesRead += buffer.Length;
            if (progress != null)
                progress.Report(totalBytesRead);
            await fs.WriteAsync(buffer).ConfigureAwait(false);
        }
        inputStream.Dispose();
    }
    return file.Name;
}