Using the System.Net.WebClient Asynchronously

During the Cabana at the Launch event yesterday one fellow came and had a dire problem when using the System.Net.WebClient asynchronously.  He indicated to me that all of his attempts were failing.  When there was a 404 he said that an exception was thrown and he could not catch that exception at the local scope of the calling action but only at the assembly level (Yikes!).  Another issue was that posting data was a big problem.  He indicated that he could never get it to work with any of the methods on the WebClient class to actually send data over the wire to the host.  I put together a quick code snippet of this actually working.  I realize this may not be the cleanest code or even close to being best practice but it is a working example of what the guy wanted to see.


using System;

namespace WebClientThreading {
    class Program {
        static bool finished = false;
        static string filepath = @"c:\testdata.html";
  //change the url to something like list.asp.404 or whatever to get a 404 or 405 error.
        static string url = "http://localhost/list.asp";

        static void Main(string[] args) {
            System.Net.WebClient wc = new System.Net.WebClient();
           
//uncomment if you want to try to download asynch instead of doing a form post.
            //wc.DownloadFileCompleted += new System.ComponentModel.AsyncCompletedEventHandler(wc_DownloadFileCompleted);
            //wc.DownloadFileAsync(new Uri(url), filepath);
            //wc.DownloadProgressChanged += new System.Net.DownloadProgressChangedEventHandler(wc_DownloadProgressChanged);

 //add items to POST up.  These will show in the Request.Form collection
            System.Collections.Specialized.NameValueCollection items = new System.Collections.Specialized.NameValueCollection();
            items.Add("text", "this is a test");
           
wc.UploadValuesCompleted+=new System.Net.UploadValuesCompletedEventHandler(wc_UploadValuesCompleted);
            wc.UploadValuesAsync(new Uri(url), items);

            //sleep until the asynch operations have completed
            while (!finished) {
                System.Threading.Thread.Sleep(1000);
            }           
           
        }

        static void wc_UploadValuesCompleted(object sender, System.Net.UploadValuesCompletedEventArgs e) {
            if (e.Cancelled != null) Console.WriteLine(e.Cancelled.ToString());
            if (e.Error != null) Console.WriteLine(e.Error.ToString());
            if (e.UserState != null) Console.WriteLine(e.UserState.ToString());
            try {
                if (e.Result != null) {
                    if (System.IO.File.Exists(filepath)) System.IO.File.Delete(filepath);
                    if (e.Result is System.Byte[]) {
                        System.IO.FileStream fs = new System.IO.FileStream(filepath, System.IO.FileMode.CreateNew);
                        fs.Write(e.Result, 0, e.Result.Length);
                        fs.Close();
                        Console.WriteLine(System.Text.ASCIIEncoding.Default.GetString(e.Result));
                    } else {
                        Console.WriteLine(e.Result.ToString());
                        System.IO.StreamWriter sw = new System.IO.StreamWriter(filepath);
                        sw.Write(e.Result);
                        sw.Close();
                        Console.WriteLine(e.Result);
                    }
                }
            } catch (Exception exc) {
   //calling e.Result will throw an exception at the local scope when it encouters something like a 404 or a 405, so I catch it here.  You will need to handle this appropriately.
                string f = exc.ToString();
            }
            finished = true;
        }


        static void wc_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e) {
            if (e.Cancelled != null) Console.WriteLine(e.Cancelled.ToString());
            if (e.Error != null) Console.WriteLine(e.Error.ToString());
            if (e.UserState != null) Console.WriteLine(e.UserState.ToString());

            finished = true;
        }

        static void wc_DownloadProgressChanged(object sender, System.Net.DownloadProgressChangedEventArgs e) {
            Console.WriteLine(e.ProgressPercentage);
        }

    }
}

 

Here is the contents of list.asp (its old school classic asp only because I had the script sitting there since the old days, just easier and quicker to pull it up).

<%
Response.Write now
%>

<table border="1"><tr><td><b>Form Items</b></td></tr><tr><td>Name</td><td>Value</td></tr>
<%
for each item in request.form
 response.write "<tr><td>" & item & "</td><td>" & request.form(item) & "</td></tr>"
next
%>
<table>

 

2 Comments

  • Gert said

    How do i confirm that the file that I downloaded is correct or that my download was succesful? Even if I check the e.Error state when the download complete event fire when I pulled the network cable - I cant see that an exception happened. I would like to resume/retry when something went wrong. Here is how I check the download complete event: void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e) { if(e.Cancelled) MessageBox.Show("Cancelled!"); if (e.Error != null) MessageBox.Show("Error" + e.Error.Message); if (e.UserState != null) MessageBox.Show("Error" + e.UserState.ToString()); MessageBox.Show("Done!"); }

Comments have been disabled for this content.