.NET Framework Developer Center >
.NET Development Forums
>
Network Class Library (System.Net)
>
Canceling async download on app termination
Canceling async download on app termination
- I need an advice on how to gracefully cancel an async download when the application is closing.
Let's say I have a WebClient downloading some file via DownloadFileAsync(). I want to be sure the file is downloaded completely, so, I set DownloadFileCompleted to a handler which removes the file if e.Error or e.Cancelled is set. If I need to cancel the download I call CancelAsync() and the handler is called (although not immediately) and does its job. But not when the application is terminating. It looks like in this case the application closes before the handler is called. Even if I wait for !webclient.IsBusy after CancelAsync().
I solved this problem by moving the cancel/error handling code to a separate function and now my code looks like:
private void MyOnDownloadCompleted(...)
{
if (e.Error != null || e.Cancelled)
{
MyCancelAndErrorHandler();
}
...
}
public void CancelDownload()
{
// If canceling the download NOT on the application termination,
// this prevents the MyCancelAndErrorHandler from being called twice.
webclient.DownloadFileCompleted -= MyOnDownloadCompleted;
webclient.CancelAsync();
while (webclient.IsBusy)
{
Thread.Sleep(100);
}
MyCancelAndErrorHandler();
}
This works, but looks ugly. I don't like the Sleep() loop and I don't like the mess with the MyCancelAndErrorHandler.
Is there any better way to do this? Many centuries ago in Delphi there was a very nice function Application.ProcessMessages, which could hopefully help in this case if put after Sleep(), but AFAIK, there's no such function in .NET. Any other ideas?
All Replies
There's a few options.
A quick hack is Application.DoEvents, an equivalent to the old Delphi Application.ProcessMessages. However, I can't recommend it. It's a hack.
If you're writing a Windows Forms application, then you could have your main form hide itself instead of close until the download completes.
-Steve
Programming blog: http://nitoprograms.blogspot.com/
Including my TCP/IP .NET Sockets FAQ
Microsoft Certified Professional Developer- The problem is I'm trying to create just a class, not an application. So, it does not know if the application is a WF, WPF or just a console one. I suspect that Application.DoEvents will not help in this case too.
And I suspect that any background thread will have the same problem, not just WebClient.
- In that case, you need to define an explicit foreground thread to wait for the operation to complete. The ActionThread from the Nito.Async library (http://www.codeplex.com/NitoAsync) may be useful here: it's a foreground thread that supports completion notifications (e.g., WebClient.DownloadFileCompleted).
-Steve
Programming blog: http://nitoprograms.blogspot.com/
Including my TCP/IP .NET Sockets FAQ
Microsoft Certified Professional Developer - Thanks, this looks like what I was looking for or at least a good code to study. :)
- In case someone else is interested, I've found a rather simple alternative to DoEvents(). Not sure how reliable it is, but looks working. Just make the dispatcher invoke something. This causes the message queue to be processed so that the webclient's DownloadFileCompleted delegate can be called.
System.Windows.Threading.Dispatcher.CurrentDispatcher.Invoke(
System.Windows.Threading.DispatcherPriority.Background,
new Action(delegate{})); - Found yet another surprise. It looks like Thread.Sleep() called in a background thread processes the posted messages. At least I can see some delegates called in the same thread after Sleep() is entered but before the thread really sleeps.


