Reputation: 8892
I am new to the whole Async
and Threading
world of the programming. And I am stuck at one problem. Following code is simplified version for the better understanding.
What I am trying to do the three things,
1) Hit api in loop using WebClient
and it's Async
method and start downloading the data
2) While downloading the api data use that time to process the other data and calculate some values
3) Make sure all downloading is completed and then process downloaded data and save to the file and database
I am able to achieve 2 steps but In 3rd step I am not sure how I can detect if all download is completed or not so Googled and found this but the problem with that it requires .net 4.5 and I am working on the .net 4.0. So basically I need solution that will help me figure out how to detect if download of all api calls is completed.
There is one way that use loop call count to match the completed data item list count but what if only one or two api calls get error in that case it will wait indefinitely.
Below is my code,
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);
}
}
}
Feel free to comment in case of confusion . If there is any other way to achieve what I am doing then please free to mention. No need to follow my approach, If you have any-other please free to comment.Any pointers to words the answers will be great.
Upvotes: 0
Views: 765
Reputation: 14856
As a side note, you can use Microsoft Async to use async-awit
on .NET 4.0
So, you need to have some way to wait for the end of a series of "tasks".
Since you seem to know how many "tasks" you have, a CountdownEvent is a good fit:
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();
}
}
}
Upvotes: 2