views:

36

answers:

3

I'm currently writing a C# console app that generates a number of urls that point to different images on a web site and then downloads those URLs as byte streams using WebClient.DownloadDataAsync.

My issue is that once the first asynchronous call is made, the console app considers the program to be completed and terminates before the asynchronous call can return. By using a Console.Read() I can force the console to stay open but this doesn't seem like very good design. Furthermore if the user hits enter during the process (while the console is waiting for input) the program will terminate.

Is there a better way to prevent the console from closing while I am waiting for an asynchronous call to return?

Edit: the calls are asynchronous because I am providing a status indicate via the console to the user while the downloads take place.

+5  A: 

Yes. Use a ManualResetEvent, and have the async callback call event.Set(). If the Main routine blocks on event.WaitOne(), it won't exit until the async code completes.

The basic pseudo-code would look like:

static ManualResetEvent resetEvent = new ManualResetEvent(false)

static void Main()
{
     CallAsyncMethod();
     resetEvent.WaitOne(); // Blocks until "set"
}

void DownloadDataCallback()
{
     // Do your processing on completion...

     resetEvent.Set(); // Allow the program to exit
}
Reed Copsey
Thanks! This makes sense and works perfectly... much better than console.read!
Andrew
A: 

That's because it's asynchronous and happens in a separate thread to the main console thread.

The most simplest solution is to simply mark a flag, for example:

bool do_wait = true;
DoAsyncCall();

while (do_wait) Thread.Sleep(100);

Then in the async call:

private void DoAsyncCall()
{
  ...
  do_wait = false;
}

I'm simplifying things somewhat here and missing out any locking and proper async code but you get the idea I hope.

However I agree with Andrew Barber's reply, for this you might as well go synchronous.

Lloyd
Using a WaitHandle (such as a ManualResetEvent) is much better than a boolean + sleep. Also, if you're going to do this, make sure to mark the bool as volatile...
Reed Copsey
Yes that is true.
Lloyd
+1  A: 

If that is all your application is doing, I would suggest leaving out the async call; you specifically want the app to 'hang' until the download is complete, so using an async operation is contrary to what you want here, especially in a console app.

Andrew Barber
I left this out in my problem explanation but during the download I display a progress indicator to the console window. We are talking thousands of images so it will be valuable to the end user to know what is going on.
Andrew
That's fine; you can still update the console from the same thread, too; the user just won't be able to do anything but Control-C out, but that's the behavior you are looking for, anyway.
Andrew Barber
@Andrew: Using async can also be beneficial if you ever need to extend this to download multiple files, etc... wasn't sure of the rationale here, but if it's just one file, synchronous would be easier..
Reed Copsey
@Reed I should have been clearer that I was assuming he's only doing a single file, yes. Thanks, Reed! +1
Andrew Barber