检测webclient的DownloadComplete事件处理程序执行是否已完成?

时间:2015-02-06 14:21:39

标签: c# multithreading asynchronous .net-4.0 async-await

我是编程的整个AsyncThreading世界的新手。而且我遇到了一个问题。以下代码是简化版本,以便更好地理解。

我想做的三件事,

1)使用WebClientAsync方法在循环中点击api并开始下载数据
  2)下载api数据时使用该时间处理其他数据并计算一些值
  3)确保完成所有下载,然后处理下载的数据并保存到文件和数据库

我能够实现2个步骤但是在第3步中我不知道如何检测是否所有下载都已完成所以用Google搜索并找到this但问题是它需要.net 4.5和我我正在研究 .net 4.0 。所以基本上我需要的解决方案可以帮助我弄清楚如何检测所有api调用的下载是否已完成。

有一种方法可以使用循环调用计数来匹配已完成的数据项列表计数,但是如果只有一个或两个api调用得到错误,那么它将无限期地等待。

以下是我的代码,

  class Program
  {
    public static List<StackRoot> AllQuestionRoot = new List<StackRoot>();
    static void Main(string[] args)
    {
        MyWebClient client = new MyWebClient();
        try
        {
            for (int i = 0; i < 10; i++)
            {
                client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(HandleQuestionDownloadCompleted);
                client.DownloadStringAsync(new Uri("http://api.stackexchange.com/2.2/questions?page=1&pagesize=20&order=desc&sort=creation&tagged=reporting-services&site=stackoverflow"), waiter);
            }
        }
        catch (WebException exception)
        {
            string responseText;
            using (var reader = new StreamReader(exception.Response.GetResponseStream()))
            {
                responseText = reader.ReadToEnd();
            }
        }
        //Do some other stuff
        //calculate values 

        //How to make sure all my asynch DownloadStringCompleted calls are completed ?

        //process AllQuestionRoot data  depending on some values calculated above

        //save the AllQuestionRoot to database and directory

       Console.ReadKey();
    }

    private static void HandleQuestionDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        if (e.Error == null || !e.Cancelled)
        {
            StackRoot responseRoot = JsonConvert.DeserializeObject<StackRoot>(e.Result);

            AllQuestionRoot.Add(responseRoot);
        }
    }
}

如果出现混淆,请随时发表评论。如果有任何其他方式来实现我正在做的事情,请随意提及。没有必要按照我的方法,如果你有任何其他请自由评论。任何指向单词的答案将是伟大的。

1 个答案:

答案 0 :(得分:2)

作为旁注,您可以使用Microsoft Async .NET 4.0

上使用async-awit

所以,你需要有一些方法等待一系列&#34;任务的结束&#34;。

因为你似乎知道有多少&#34;任务&#34;你有,CountdownEvent非常合适:

  class Program
  {
    public static List<StackRoot> AllQuestionRoot = new List<StackRoot>();
    public static object criticalSection = new object();
    public static CountdownEvent countdown = new CountdownEvent(10);
    static void Main(string[] args)
    {
        MyWebClient client = new MyWebClient();
        try
        {
            for (int i = 0; i < 10; i++)
            {
                client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(HandleQuestionDownloadCompleted);
                client.DownloadStringAsync(new Uri("http://api.stackexchange.com/2.2/questions?page=1&pagesize=20&order=desc&sort=creation&tagged=reporting-services&site=stackoverflow"), waiter);
            }
        }
        catch (WebException exception)
        {
            string responseText;
            using (var reader = new StreamReader(exception.Response.GetResponseStream()))
            {
                responseText = reader.ReadToEnd();
            }
        }
        //Do some other stuff
        //calculate values 

        //How to make sure all my asynch DownloadStringCompleted calls are completed ?

        //process AllQuestionRoot data  depending on some values calculated above

        //save the AllQuestionRoot to database and directory

        // Wait until all have been completed.
        countdown.Wait();

        Console.ReadKey();
    }

    private static void HandleQuestionDownloadCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        if (e.Error == null || !e.Cancelled)
        {
            StackRoot responseRoot = JsonConvert.DeserializeObject<StackRoot>(e.Result);

            // Adding to List<T> is not thread safe.
            lock (criticalSection)
            {
                AllQuestionRoot.Add(responseRoot);
            }

            // Signal completed. 
            countdown.Signal();
        }
    }
}