简体   繁体   English

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

[英]WebClient freezes when async-downloading a second file if I'm getting the original filename from Content-Disposition

I'm writing an application that manages a library of mods/addons for a game. 我正在编写一个用于管理游戏的mods / addons库的应用程序。 Every so often, one of these mods has an update available, and the new version is downloaded using WebClient.DownloadFileAsync(), having retrieved the filename through reading the Content-Disposition in a WebRequest response. 这些mod之一经常都有可用的更新,并且已通过读取WebRequest响应中的Content-Disposition检索了文件名,并使用WebClient.DownloadFileAsync()下载了新版本。

When two or more updates are available, the first downloads perfectly fine but when you try to download a second file without having restarted the application WebClient freezes, the file is created with the retrieved name, but contains 0 bytes and neither the DownloadProgressChanged or DownloadFileCompleted events are triggered. 当有两个或多个更新可用时,第一个下载就很好,但是当您尝试下载第二个文件而没有重新启动应用程序时,WebClient冻结,该文件将使用检索到的名称创建,但包含0个字节,并且DownloadProgressChanged或DownloadFileCompleted事件都不被触发。

If I do not try to retrieve the original filename, and just give them a name locally, then WebClient doesn't freeze. 如果我不尝试检索原始文件名,而只是在本地为其命名,则WebClient不会冻结。 But I need the original filename. 但是我需要原始文件名。

Is there anything I can do to avoid this issue, while still being able to retrieve the original filename? 在仍然能够检索原始文件名的同时,我可以做些什么来避免此问题?

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)
{
    // ...
}

I had the same problem. 我有同样的问题。 After hours and hours on end i found out that the problem was in a stream which was not disposed. 数小时之后,我发现问题出在没有解决的问题中。 I used it to check weather a file exists in a web directory. 我用它来检查天气,网页目录中是否存在文件。

    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;
    }

Actually I replicated the same code you have in a WPF client. 实际上,我复制了WPF客户端中的相同代码。 I reproduced the problem but from the 1st file. 我重现了问题,但来自第一个文件。 I found a 0 bytes length file created locally but no content. 我发现本地创建了一个0字节长的文件,但没有内容。

In my case the solution I added was to set the user credentials, after which I was able to download multiple files, and repeatedly (stepping on previous downloads). 在我的情况下,我添加的解决方案是设置用户凭据,此后,我可以下载多个文件并反复下载(逐步执行以前的下载)。

I added this line: wc.Credentials = CredentialCache.DefaultCredentials; 我添加了这一行: 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);
}

I managed to fix the problem by passing the instance of WebClient that was downloading the file through the EventHandler's parameters and then using that to get the original filename, rather than using a seperate instance of it to retrieve the filename. 我设法通过通过事件处理程序的参数传递要下载文件的WebClient实例,然后使用它来获取原始文件名,而不是使用它的单独实例来检索文件名,来解决此问题。

Credit to this question for helping me figure out the solution. 感谢这个问题帮助我找出了解决方案。

With this solution, because I can't find out the original filename until after the file has been downloaded, I assign it a temporary name for the download, and rename it when the download is complete in the AsyncCompletedEventHandler. 使用此解决方案,因为直到下载完文件后我才能找到原始文件名,所以我为文件分配了一个临时名称,并在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);
    }

    // ...
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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