【问题标题】:WebClient freezes when async-downloading a second file if I'm getting the original filename from Content-Disposition如果我从 Content-Disposition 获取原始文件名,WebClient 会在异步下载第二个文件时冻结
【发布时间】:2013-05-26 03:50:09
【问题描述】:

我正在编写一个应用程序来管理游戏的模组/插件库。每隔一段时间,其中一个模块就有可用的更新,新版本是使用 WebClient.DownloadFileAsync() 下载的,通过读取 WebRequest 响应中的 Content-Disposition 检索文件名。

当有两个或更多更新可用时,第一个下载非常好,但是当您尝试下载第二个文件而不重新启动应用程序时,WebClient 冻结,该文件使用检索到的名称创建,但包含 0 个字节,并且 DownloadProgressChanged或触发 DownloadFileCompleted 事件。

如果我不尝试检索原始文件名,而只是在本地为它们命名,则 WebClient 不会冻结。但我需要原始文件名。

我可以做些什么来避免这个问题,同时仍然能够检索原始文件名?

private void Download(string url, string downloadDirectory)
{
    WebClient wc = new WebClient();
    string filename = FilenameFromURL(url);

    wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
    wc.DownloadFileCompleted += new AsyncCompletedEventHandler(DownloadComplete);

    wc.DownloadFileAsync(new Uri(url), downloadDirectory + filename);
}

private string FilenameFromURL(string url)
{
    return new ContentDisposition(WebRequest.Create(url).GetResponse().Headers["Content-Disposition"].ToString()).FileName;
}

private void DownloadProgress(object sender, DownloadProgressChangedEventArgs e)
{
    downloadProgressBar.Value = e.ProgressPercentage;
}

private void DownloadComplete(object sender, AsyncCompletedEventArgs e)
{
    // ...
}

【问题讨论】:

  • 您确定您没有在某处吞下异常吗?您是否厌倦了一些 HTTP 调试?以 Fiddler 为例?

标签: c# asynchronous download webclient filenames


【解决方案1】:

我遇到了同样的问题。经过几个小时后,我发现问题出在未处理的流中。我用它来检查 web 目录中是否存在文件。

    private bool WebFileExists(string url)
    {
        bool exists = true;

        try
        {
            using (WebClient testClient = new WebClient())
            {
                testClient.Credentials = new NetworkCredential(_userName, _password);
                Stream stream = testClient.OpenRead(url);
                stream.Dispose();
            }
        }
        catch
        {
            exists = false;
        }

        return exists;
    }

【讨论】:

  • 非常感谢。它真的节省了一天寻找解决方案
【解决方案2】:

我设法解决了这个问题,方法是通过 EventHandler 的参数传递正在下载文件的 WebClient 实例,然后使用它来获取原始文件名,而不是使用它的单独实例来检索文件名。

感谢 this question 帮助我找出解决方案。

使用此解决方案,因为直到文件下载后才能找到原始文件名,所以我为下载分配了一个临时名称,并在下载完成时在 AsyncCompletedEventHandler 中重命名。

private void Download(string url, string downloadDirectory)
{
    WebClient wc = new WebClient();

    wc.DownloadProgressChanged += new DownloadProgressChangedEventHandler(DownloadProgress);
    wc.DownloadFileCompleted += new AsyncCompletedEventHandler((sender, e) => DownloadComplete(sender, e, wc));

    wc.DownloadFileAsync(new Uri(url), downloadDirectory + "temp");
}

private void DownloadProgress(object sender, DownloadProgressChangedEventArgs e)
{
    downloadProgressBar.Value = e.ProgressPercentage;
}

private void DownloadComplete(object sender, AsyncCompletedEventArgs e, WebClient wc)
{
    string filename = new ContentDisposition(wc.ResponseHeaders["Content-Disposition"].ToString()).FileName;
    if (File.Exists(downloadDirectory + "temp"))
    {
        if (File.Exists(downloadDirectory + filename))
            File.Delete(downloadDirectory + filename);
        File.Move(downloadDirectory + "temp", downloadDirectory + filename);
    }

    // ...
}

【讨论】:

  • 这比您原来的解决方案要好得多...您的“GetFileNameFromUrl”方法开始从服务器下载文件,但从不获取文件内容...昂贵的服务器往返,以及被丢弃的 Web 请求,不知道何时(垃圾收集器何时去获取它)。为了进一步改善这一点,请使用 .NET 4.5 中的 TaskAsync 重载和 TAP 工作流,而不是“EventHandler”方法。
【解决方案3】:

实际上,我复制了您在 WPF 客户端中的相同代码。我从第一个文件中重现了这个问题。我发现在本地创建了一个 0 字节长度的文件,但没有内容。

在我的情况下,我添加的解决方案是设置用户凭据,之后我可以下载多个文件,并且可以重复(踩到以前的下载)。

我添加了这一行:wc.Credentials = CredentialCache.DefaultCredentials;

private void Download(string url, string downloadDirectory, string fileName)
{
    WebClient wc = new WebClient();
    wc.Credentials = CredentialCache.DefaultCredentials;

    wc.DownloadProgressChanged += DownloadProgress;
    wc.DownloadFileCompleted += DownloadComplete;
    wc.DownloadFileAsync(new Uri(url), downloadDirectory + fileName);
}

【讨论】:

  • 无论是否被 using 语句包裹,第二个文件下载仍然冻结。
  • 丢弃仍在使用的对象是自找麻烦。
猜你喜欢
  • 2013-12-27
  • 2012-05-18
  • 2016-03-23
  • 2021-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-12-06
相关资源
最近更新 更多