0

I am trying to upload a file via FTP, and want to report progress to the user. I was following this suggestion, but couldn't make it work.

If I call the code synchronously, it works fine...

  FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://myftpserver.com/test.zip");
  request.Credentials = new NetworkCredential("uid", "pwd");
  request.Method = WebRequestMethods.Ftp.UploadFile;
  using (FileStream inputStream = File.OpenRead(@"D:\test.zip")) {
    using (Stream outputStream = request.GetRequestStream()) {
      byte[] buffer = new byte[64 * 64];
      int totalReadBytesCount = 0;
      int readBytesCount;
      while ((readBytesCount = inputStream.Read(buffer, 0, buffer.Length)) > 0) {
        outputStream.Write(buffer, 0, readBytesCount);
        totalReadBytesCount += readBytesCount;
        int progress = (int)(totalReadBytesCount * 100.0 / inputStream.Length);
        Debug.WriteLine("  " + progress + "%");
      }
    }
  }

...but if I try and wrap the code in a BackgroundWorker, it fails silently. I have tried adding a try/catch block around it, but I don't get an exception.

Here is the BGW version of the code...

  BackgroundWorker bg = new BackgroundWorker {
    WorkerReportsProgress = true
  };
  bg.DoWork += (s, e) => {
    try {
      Debug.WriteLine("DoWork");
      FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://myftpserver.com/test.zip");
      Debug.WriteLine("DoWork - Setting up creds");
      request.Credentials = new NetworkCredential("uid", "pwd");
      request.Method = WebRequestMethods.Ftp.UploadFile;
      using (FileStream inputStream = File.OpenRead(@"D:\test.zip")) {
        using (Stream outputStream = request.GetRequestStream()) {
          byte[] buffer = new byte[64 * 64];
          int totalReadBytesCount = 0;
          int readBytesCount;
          while ((readBytesCount = inputStream.Read(buffer, 0, buffer.Length)) > 0) {
            Debug.WriteLine("  DoWork - Inside");
            outputStream.Write(buffer, 0, readBytesCount);
            totalReadBytesCount += readBytesCount;
            double progress = totalReadBytesCount * 100.0 / inputStream.Length;
            Debug.WriteLine("  " + progress + "%");
            bg.ReportProgress((int)progress);
          }
        }
      }
    }
    catch (Exception ex) {
      Debug.WriteLine("Exception: " + ex.Message);
    }
  };
  bg.ProgressChanged += (s, e) => {
    Debug.WriteLine(e.ProgressPercentage + "%");
  };
  bg.RunWorkerCompleted += (s, e) => {
    Debug.WriteLine("Done");
  };
  bg.RunWorkerAsync();
}

I get the "DoWork" line written to the Output window, but then nothing else. If I put a breakpoint on the line that sets up the FtpWebRequest, execution immediately ends after that line, but I don't get an exception.

Anyone any ideas? Could be I'm doing this wrong. I want to upload async, and have a progress indicator. Is this even the best way to do it?

Community
  • 1
  • 1
Avrohom Yisroel
  • 8,555
  • 8
  • 50
  • 106
  • Try removing the "DoWork" debug line and see what happens? You should get the 2nd DoWork line. – jdweng Jul 05 '15 at 13:46
  • @jdweng nope, didn't get anything then – Avrohom Yisroel Jul 05 '15 at 13:49
  • The create isn't completing. Did you wait long enough? Try original code again and make sure it still is working. The server may be ignoring the request. The could be something wrong with the cookie. I would go into IE and delete history and try again. This will remove all cookies and the server may start responding again. – jdweng Jul 05 '15 at 15:39
  • @jdweng yes the original code is working fine. I can comment out the async bits and run it, and it's fine, so I don't think it's anything to do with the server or cookies. Any other ideas? Thx – Avrohom Yisroel Jul 05 '15 at 15:50
  • Did you comment out the Sync line so you aren't running two creates()? Not sure all your looping in your code. Is it failing the 1st time you are running Create() method? – jdweng Jul 05 '15 at 16:19
  • I only ever call Create() the once. If I do it without the BGW then it works fine, if I wrap it in the BGW, then the execution ends directly after hitting the call to Create(), but without any exceptions. The looping in the async version was to get the progress, but the code never gets that far. – Avrohom Yisroel Jul 05 '15 at 16:23
  • Try creating the request in the main thread an pass the request to the background worker. – jdweng Jul 05 '15 at 18:43
  • OK, I have no idea what's going on here. I moved the request out as you suggested, and added a Debug.WriteLine between pretty much every line. I can hit f5 repeatedly, and it stops after a few lines, but not necessarily the same place every time. Whenever it stops, it does so without an exception, it just seems to give up. How on earth am I supposed to work out what's going on? I can't even give you a definitive answer as to where it breaks. I'm totally baffled. – Avrohom Yisroel Jul 05 '15 at 18:54
  • Based on the fact that your code stops in different places and you don't break on the catch exception, I would check if maybe you get an exception from another thread. When you do the async upload, do your code do other things as well? Also try to enable breaking on all exceptions (in debug -> exceptions), maybe you'll pick up the issue there. – tzachs Jul 05 '15 at 21:52
  • @tzachs The code I showed in my post is the entire code, there's nothing else going on in this sample project. It's a console window project, and the code shown above was inside the Main() method. As for the exceptions, I suspect there's something funny going on here, as I can press f5 several times, and see different results in the output window. That's not normal! – Avrohom Yisroel Jul 06 '15 at 14:36
  • Anyone? I just don't know where to go from here. – Avrohom Yisroel Jul 07 '15 at 16:23
  • Turns out that because I was running this code in a console app for testing, the app was exiting before the async method had finished, hence the end of execution without any errors. Keeping the main app alive solved the problem. – Avrohom Yisroel Jul 07 '15 at 19:20

1 Answers1

0

In case it helps anyone, the problem was nothing to do with the upload code, which was fine. The problem was that, for speed (or so I thought) I was developing this bit of code in a console application. The Main() method called the async upload method, then exited. The reason for the problem was that the Main method wasn't waiting until the async method had finished, so execution was terminated.

The quick and dirty way to get around the problem was to add the line...

Thread.Sleep(10000);

...after the call to the async method. However, this requires guessing how long the async method will need, and/or being conservative and having to wait longer than necessary.

A better approach, which only requires waiting as long as it needed can be seen in IWolber's answer in this thread.

Avrohom Yisroel
  • 8,555
  • 8
  • 50
  • 106