Framework Madness!

And other adventures C# and asp.net …

Async Only – Using the Background Worker with FTPWebRequest (Part 2 – sort of)

with one comment

In the article Async Async – Using BackgroundWorker and WebClient async upload together (Part 1) I covered the use of the BackgroundWorker and planed to use the WebClient to upload files via FTP.

And so it was that WebClient didn’t support timeouts, nor did it error out correctly if the receiving FTP sever didn’t correctly.

When I moved testing from my local test machine to a staging server smaller FTP uploads worked like a charm, but larger files (50 MB) plus sever seemed to complete. So I stopped using System.Net.WebClient for FTP uploads and switched to FTPWebRequest so I could investigate where the hang up was. Here is the code for using FTPWebRequest to upload a file:

Here is what it does:

   1: private void OnExecuteProcess(FtpWebRequest request)
   2: {
   3:    if (request != null)
   4:    {
   5:       
   6:  
   7:        const int bufferLength = 2048;
   8:        byte[] buffer = new byte[bufferLength];
   9:        int count = 0;
  10:        int readBytes = 0;
  11:        Stream requestStream = null;
  12:  
  13:        using (FileStream stream = File.OpenRead(this.Delivery.Source.FilePath))
  14:        {
  15:            requestStream = request.GetRequestStream();           
  16:  
  17:            do
  18:            {
  19:                readBytes = stream.Read(buffer, 0, bufferLength);
  20:                requestStream.Write(buffer, 0, readBytes);
  21:                count += readBytes;
  22:                
  23:            }
  24:            while (readBytes != 0);
  25:  
  26:            this.isWriteComplete = true;
  27:  
  28:        }
  29:  
  30:        //here is were we get hung up and it throws an exception
  31:        requestStream.Close();
  32:       
  33:        //get the response
  34:        request.GetResponse().Close();
  35:  
  36:    }
  37: }

1) Not shown yet – but this method is called inside a try/finally block so it should not bring the process down.

2) A FileStream is opened based on a object level variable. FileStream allows us to copy out portions of the file instead of the whole thing.

3) A RequestStream is opened from FTPWebRequest. This will allow is to pour in data from file stream and send it to the server.

4) A simple Do/While loop is used to transfer file bytes.

5) When the write process is complete is track in a local variable that the write process is completed.

6) We clean up.

So good so far. If the code looks familiar that’s it because it’s from the FtpWebRequest documentation.

But let’s take a look inside two more code blocks. Here is the method that calls OnExcecuteProcess:

   1: private void OnExecute()
   2: {
   3:     this.Initalize();
   4:  
   5:     FtpWebRequest request = null;
   6:  
   7:     try
   8:     {
   9:        
  10:  
  11:         //build the request
  12:         request = (FtpWebRequest)WebRequest.Create(this.Location.Uri);
  13:         
  14:         request.Method = WebRequestMethods.Ftp.UploadFile;
  15:  
  16:         //build the credentials
  17:         request.Credentials = new NetworkCredential(this.Delivery.Target.Username, this.Delivery.Target.Password);
  18:  
  19:         request.Timeout = 30000;
  20:  
  21:         OnExecuteProcess(request);
  22:  
  23:  
  24:     }
  25:     catch (Exception ex)
  26:     {
  27:        
  28:  
  29:         try
  30:         {
  31:             if (request != null)
  32:             {
  33:                 request.Abort();
  34:             }
  35:         }
  36:         finally
  37:         {
  38:             this.error = ex;
  39:             this.LogProgress(ex.GetPrimary().Message);
  40:         }
  41:  
  42:         
  43:  
  44:     }
  45:     finally
  46:     {
  47:         this.IsComplete = true;
  48:  
  49:         this.OnUploadComplete();
  50:     }
  51: }

Nothing really dramatic. We build the request, set the method, credentials and timeout and pass to OnExecuteProcess. The ‘catch’ block contains a ‘request.Abort’ call and logs the exception. The ‘finally’ block the IsComplete property and calls OnUploadComplete, which triggers a corresponding event.

But here is where we compensate for the failed request completion or response in the Error property.

   1: private Exception error;
   2:  
   3: public Exception Error
   4: {
   5:    get
   6:    {
   7:        if (this.isWriteComplete)
   8:        {
   9:            return null;
  10:        }
  11:  
  12:        return error;
  13:    }
  14: }

In the first code block I set isWriteComplete to true after writing my bytes. Here is where I am using the isWriteComplete property to control error returns.If the logging code sees an error it logs a non-download, so this code avoids returning an error if all the bytes were written to the response stream.

Now as I am writing here I am thinking it’s probably better to return an IsWriteComplete property along with IsComplete, always return the exception, and pass along the logic to the logging tool. I’ll try that and get back with you.

Advertisements

Written by Lynn Eriksen

January 19, 2009 at 10:22 pm

Posted in Uncategorized

One Response

Subscribe to comments with RSS.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: