使用带有Cookie感知Webclient的DownloadDataAsync来获取更新进度

时间:2012-04-17 06:10:15

标签: c# winforms

我正在使用带有CookieContainer的Webclient从Web服务(Sharepoint)下载数据。

我想要DownloadDataAsync,以便下载多个文档并在下载时为每个文档更新一个进度条。非异步版本 - DownloadData不会发送进度更新。

  1. 如何在继续下一个文档之前让异步版本在doc.BinaryData = xx行等待?
  2. 如何从DownloadFileCompleted事件中获取字节数组?
  3. 如何在不使用DoEvents的情况下将更改应用于进度条?

    部分类Form() {     void Main()     {         列表urls = new List();         //urls.Add("xxxxxxx“); //从某个地方获取它们

        for (int i = 0; i < urls.Count; i++)
        {
            var doc = new Document();
            doc.BinaryData = DocumentAsArray(urls.ElementAt(i));
            entities.AddToDocument(doc);
        }
    }
    
    public byte[] DocumentAsArray(string URL)
    {
        byte[] @return = null;
        using (CookieAwareWebClient client = new CookieAwareWebClient())
        {
            client.CookieContainer = spAuthentication.CookieContainer;
    
            // Assign the events to capture the progress percentage
            client.DownloadFileCompleted += new AsyncCompletedEventHandler(client_DownloadFileCompleted);
            client.DownloadProgressChanged += new DownloadProgressChangedEventHandler(client_DownloadProgressChanged);
    
            client.DownloadDataAsync(new Uri(URL));
        }
    
        return @return;
    }
    
    void client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
    {
        progressBarControlFile.Position = e.ProgressPercentage;
        var newPc = string.Format("Downloaded {0} %", e.ProgressPercentage);
    
        labelControlFile.Text = newPc;
        Application.DoEvents();
    }
    
    void client_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
    {
        progressBarControlFile.Position = progressBarControlFile.Properties.Maximum;
        labelControlFile.Text = string.Format("{0} %", progressBarControlFile.Properties.Maximum);
    
        Application.DoEvents();
    }
    

    }

    公共类CookieAwareWebClient:WebClient {     公共CookieContainer CookieContainer {get;组; }

    protected override WebRequest GetWebRequest(Uri address)
    {
        WebRequest request = base.GetWebRequest(address);
    
        var webRequest = request as HttpWebRequest;
        if (webRequest != null)
        {
            webRequest.CookieContainer = this.CookieContainer;
            webRequest.KeepAlive = false;
        }
    
        return request;
    }
    

    } }

1 个答案:

答案 0 :(得分:1)

  1. 您必须等待DownloadFileCompleted事件。您可以设置轮询的volatile bool或使用事件执行此操作。性能方面只有微小的差异,但一般情况下事件可能是更清晰的解决方案(我更喜欢bool-polling)。在您的情况下,您可能希望等到DocumentAsArray结束时发生这种情况。
  2. http://msdn.microsoft.com/en-us/library/ms144190.aspx下载的数据可在Result属性中找到。
  3. 我不知道DoEvents方法 - 如果我理解你想要做什么,你想更新你的用户界面吗?你必须调用InvokeEx(至少这是我知道的最简单和唯一的方式)。看看这篇很棒的文章http://www.andreas-reiff.de/2011/06/accessing-a-winformwpf-control-from-another-thread-through-invoke/。或者,留在stackoverflow并查看Best Way to Invoke Any Cross-Threaded Code?
  4. 所以回顾一下,如果你只是想让异步获得进度更新,只需更改你的DocumentAsArray函数,等待1中所述的DownloadFileCompleted事件。那么你所要做的就是要小心你不要从另一个线程调用你的UI代码 - 你应该在Debug中得到一个异常,告诉你不要这样做(它在Release中运行良好 - 大部分时间都是如此)。所以使用InvokeEx调用。