Bad Retreating Solution
You can save the exception in some variable defined outside of the lambda. Then it can be reset:
Exception exc = null; using (WebClient wc = new WebClient()) { wc.DownloadFileCompleted += ((sender, args) => ... mr.WaitOne(); if (exception != null) throw exception; }
Why is that bad? Since you will lose stacktrace (it will show that the exception was thrown in the current method and not in the WebClient). However, if you don't need or care about stacktrace, a solution is possible.
In-place exception handling
You can also just create some method that will handle the exception both in an external try-catch and in a loaded handler:
void HandleWebClientException(Exception exc) { ... } try { ManualResetEvent mr = new ManualResetEvent(false); mr.Reset(); using (WebClient wc = new WebClient()) { wc.DownloadFileCompleted += ((sender, args) => { if (args.Error == null) { File.Move(filePath, Path.ChangeExtension(filePath, ".jpg")); mr.Set(); } else { HandleWebClientException(args.Error); } }); wc.DownloadFileAsync(new Uri(string.Format("{0}/{1}", Settings1.Default.WebPhotosLocation, Path.GetFileName(f.FullName))), filePath); mr.WaitOne(); } } catch (Exception ex) { HandleWebClientException(ex); }
Correct execution
The best idea is to avoid void methods on WebClient because you cannot wait or apply some continuation .
Such methods are convenient in a sense, but they force you to use clandestine solutions with synchronization constructs to make the workflow less dependent on different callbacks.
To use async-wait, you need to use the public Task<byte[]> DownloadDataTaskAsync(Uri address) method.
You can:
1. await to get an array of data bytes in order to save it later manually, but this will require careful refinement of the asynchronous path in the application:
public async Task LoadFile() { try { using (WebClient wc = new WebClient()) { var bytes = await wc.DownloadDataTaskAsync(new Uri(string.Format("{0}/{1}", Settings1.Default.WebPhotosLocation, Path.GetFileName(f.FullName))), filePath); System.IO.File.WriteAllBytes(bytes);
It will work, but I'm not sure if DownloadDataTaskAsync is a true asynchronous programming method.
2. Thus, you can also use Continuations in the same way:
public Task LoadFile() { Task<Byte[]> bytesTask = wc.DownloadDataTaskAsync(new Uri(string.Format("{0}/{1}", Settings1.Default.WebPhotosLocation, Path.GetFileName(f.FullName))), filePath); var success = bytesTask.ContinueWith((prev) => { System.IO.File.WriteAllBytes(prev.Result); }, TaskContinuationOptions.OnlyOnRanToCompletion); var failure = bytesTask.ContinueWith(prev => { MessageBox.Show
PS: And why donβt you just use the simple public void DownloadFile(Uri address, string fileName) blocking method if you donβt have to upload files asynchronously?