I'm using the System.Net.FtpClient assembly to upload a file to a test FTP site. When I run the below code the file doesn't appear in the remote location unless I use a Thread.Sleep as per below (which I'd prefer not to use):
using System;
using System.IO;
using System.Net;
using System.Net.FtpClient;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
namespace FtpsUploadTest
{
/// <summary>
/// The ftp publisher.
/// </summary>
public class FtpPublisher
{
private readonly FtpsSettings _settings;
private readonly IFtpClient _ftpClient;
/// <summary>
/// Initializes a new instance of the <see cref="FtpPublisher"/> class.
/// </summary>
public FtpPublisher()
{
_ftpClient = new FtpClient();
_settings = SettingsReader.GetMySettings();
Init();
}
/// <summary>
/// The publish.
/// </summary>
/// <param name="fileToUpload">
/// The input file path.
/// </param>
public void Publish(string fileToUpload)
{
var remoteFileName = Path.GetFileName(fileToUpload);
Console.WriteLine("FTPS host: {0} remote path: {1}", _settings.FtpsRemoteHost, _settings.FtpsRemotePath);
if (!_ftpClient.IsConnected)
{
_ftpClient.Connect();
}
var fullRemotePath = string.Format("{0}/{1}", _settings.FtpsRemotePath, remoteFileName);
using (var ftpStream = _ftpClient.OpenWrite(fullRemotePath))
using (var inputStream = new FileStream(fileToUpload, FileMode.Open))
{
inputStream.CopyTo(ftpStream);
Thread.Sleep(5000); // <------------------- DOESNT WORK IF REMOVE THIS SLEEP!!
}
Console.WriteLine("File '{0}' published successfully", fileToUpload);
}
private void Init()
{
_ftpClient.Host = _settings.FtpsRemoteHost;
_ftpClient.Port = _settings.FtpsRemotePort;
_ftpClient.DataConnectionConnectTimeout = 60000;
_ftpClient.ConnectTimeout = 60000;
_ftpClient.Credentials = new NetworkCredential(_settings.FtpsUserId, string.Empty);
_ftpClient.DataConnectionType = 0;
if (string.IsNullOrEmpty(_settings.CertFile) || string.IsNullOrEmpty(_settings.CertPassword))
{
return;
}
_ftpClient.ClientCertificates.Add(CreateCertificate(_settings.CertFile, _settings.CertPassword));
_ftpClient.EncryptionMode = (FtpEncryptionMode)2;
_ftpClient.DataConnectionEncryption = true;
}
private X509Certificate CreateCertificate(string certFile, string certPassword)
{
return new X509Certificate(certFile, certPassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet);
}
}
}
Anyone know how I can get it to work without using a Thread.Sleep? I've tried flushing, closing streams but that doesn't help.
The remote FTP server is acting completely asynchronously from your code. Depending on the configuration of the server it might do things like scan for viruses or other bookkeeping before it makes the file available. There may be nothing you can do about this unless you have direct control over the FTP server. Even then it might require some pretty in depth configuration changes, or even a different software package.
One thing that might work for you is to "poll" for the file after completing the upload. Make a loop that checks for the file, waits 1 second, then repeats until it finds the file or gives up. The Async / Await pattern, or a call-back from a different thread, can help you get rid of any UI freezes from this if it's a problem.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With