The basic pattern to achieve this is to write a private function that carries out whatever operations you wish to run asynchronously. Then write a public function that starts a new thread, and pass the thread a lambda function that simply calls your internal private function. Somewhere within the internal private function, be sure to fire some events when necessary to indicate status updates or completion status.
I think the code should speak for itself. See below:
Project consists of 4 files:
EventArgs.cs
EventHandlers.cs
MyWebClient.cs
Program.cs
MyWebClient.cs:
using System; using System.Net; using System.Threading; namespace WebClientAsync { ////// Simple web client which implements an asynchronous download call using /// corresponding built in .net synchronous function calls /// public class MyWebClient { ////// Event signalling that a download is completed /// public event MyDownloadDataCompletedEventHandler DownloadDataCompleted = delegate {}; ////// Synchronous download. Simple pssthrough to .NET WebClient /// public byte[] DownloadDataSync(string url) { return new WebClient().DownloadData(url); } /// /// Asynchronous wrapper for function which calls blocking function and /// also has additional logic for determining success / failure, and firing an event public void DownloadDataAsync(string url) { new Thread(() => this.DownloadDataInternal( url )).Start(); } ////// Downloads data, which blocks calling thread. then fires an alert indicating /// completion of a download operation. Details regarding the outcome of the /// operation are also provided via the event arguments private void DownloadDataInternal(string url) { var success = true; try { this.DownloadDataSync(url); } catch( Exception ) { success = false; } DownloadDataCompleted( this, new MyDownloadDataCompletedEventArgs(success) ); } } }
EventHandlers.cs:
namespace WebClientAsync { ////// Handler for indicating an asynchronous download completion /// public delegate void MyDownloadDataCompletedEventHandler( object sender, MyDownloadDataCompletedEventArgs e ); }
EventArgs.cs:
using System; namespace WebClientAsync { ////// Contains details regarding outcome of the asynchronous download operation /// public class MyDownloadDataCompletedEventArgs : EventArgs { public bool Success { get; set; } public MyDownloadDataCompletedEventArgs(bool success) { this.Success = success; } } }
Program.cs:
using System; using System.Threading; using System.Windows.Forms; namespace WebClientAsync { class Program { ////// /// private static bool _loop = true; ////// /// static void Main(string[] args) { var url = string.Empty; if (args.Length == 1) { url = args[0]; } else { PrintUsage(); Environment.Exit(-1); } var wc = new MyWebClient(); wc.DownloadDataCompleted += DownloadDataCompleted; wc.DownloadDataAsync(url); while (_loop) { Console.WriteLine("zzz..."); Thread.Sleep(1); } Console.WriteLine("the download was finished so the loop ended. Press any key to exit"); Console.ReadKey(); } ////// /// private static void PrintUsage() { const string usageMessage = @" program.exe url e.g. program.exe http://www.google.com/somedata.txt" ; Console.WriteLine(usageMessage); } ////// /// static void DownloadDataCompleted(object sender, MyDownloadDataCompletedEventArgs e) { _loop = false; MessageBox.Show("The download completed. It was a " + (e.Success ? "Success! :)" : "Failure :(")); } } }