如果我从Content-Disposition获取原始文件名,则在异步下载第二个文件时WebClient会冻结

时间:2013-05-26 03:50:10

标签: c# asynchronous download webclient filenames

我正在编写一个管理游戏mod /插件库的应用程序。每隔一段时间,其中一个mod就有一个可用的更新,并且使用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)
{
    // ...
}

3 个答案:

答案 0 :(得分: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;
    }

答案 1 :(得分:0)

实际上我复制了你在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);
}

答案 2 :(得分:0)

我设法通过传递通过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);
    }

    // ...
}