Upload files to FTP using the WINSCP .Net library

elevator-2203695_960_720

Applications like Filezilla and WinSCP are great simple to use FTP/SFTP clients. However what about if you want to automate uploading files. Imagine you have a brilliant SSIS package, that extracts, manipulates and formats just the right data into the correct format, using SQL Server agent to run  your package early in the morning to take advantage of the gap in transactions hitting the database server. You want these extracted data files to be sent to a third party without you needing to log in open WINSCP  or Filezilla and manually upload them.

That is what we are going to look at today, a few simple methods for zipping some files and uploading them in an application that can then be set to run on a schedule with something like Windows Task Scheduler.

WINSCP .Net library

WINSCP provides  a .Net library that is a wrapper around the scripting interface available with WINSCP. This library can be used with a SSIS script task or with PowerShell among other things. However we are going to interact with it using C#, mainly because that is what I am used to.

The library has a whole range of classes up uploading and downloading files, helper classes for manipulating directory paths and getting information about the transfer.

How to Zip files

Before we upload the files we need to zip them to reduce the size of the transfer. We could do with from SSIS using a Script Task. However it is simple to do in C# as part of our FTP upload application.

Lets start off with an interface

public interface IZip
{
void SetZipFileName(string zipfileName);
void SetFilesToZip(List<string> files);
void CreateArchive();
}

view raw
IZip.cs
hosted with ❤ by GitHub

The 2 setter methods are for setting properties from outside the class, passing in the ZipFile name, which could be generated dynamically or set from a config file. The list of files could be from file system lookup of a directory looking for particular file types, or named files.

The CreateArchive method is where the file paths are looped through and added to a Zip Archive, using the name supplied. Once added to the archive each file is deleted.

using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using log4net;
public class ZipUtil : IZip
{
private static readonly ILog Log = LogManager.GetLogger(typeof(ZipModule));
private string _zipFileName;
private List<string> _files;
public void SetZipFileName(string zipfileName)
{
_zipFileName = zipfileName;
}
public void SetFilesToZip(List<string> files)
{
_files = files;
}
public void CreateArchive()
{
try
{
if (!DoAnyFilesInFileListExist())
{
Log.DebugFormat("No Files to send");
return;
}
using (var zipFile = ZipFile.Open(_zipFileName, ZipArchiveMode.Create))
{
foreach (var file in _files)
{
AddToZip(zipFile, file);
}
}
}
catch (System.IO.DirectoryNotFoundException e)
{
Log.ErrorFormat("ZIP not created as directory doesn't exist: {0}.", e.Message);
}
catch (Exception e)
{
Log.ErrorFormat("ZIP not created: {0}.", e.Message);
}
}
private bool DoAnyFilesInFileListExist()
{
foreach (var fileName in _files)
{
if (File.Exists(fileName))
{
return true;
}
}
return false;
}
private void AddToZip(ZipArchive zipFile, string fileName)
{
if (!File.Exists(fileName))
{
Log.ErrorFormat("File not added to ZIP as doesn't exist: {0}.", fileName);
return;
}
Log.DebugFormat("File added to zip: {0}", fileName);
zipFile.CreateEntryFromFile(fileName, Path.GetFileName(fileName), CompressionLevel.Optimal);
File.Delete(fileName);
}
}

view raw
ZipUtil.cs
hosted with ❤ by GitHub

How to upload the file

Now that we have the files zipped and ready to go we need to add in the WINSCP.Net library.

As we might want to upload different files to different places as part of our automation, lets add the Upload configuration to a simple class.

public class UploadConfig
{
public string Protocol { get; set; }
public string Host { get; set; }
public string User { get; set; }
public string Password { get; set; }
public string ZipFileName { get; set; }
public string RemotePath { get; set; }
public string PrivateKeyPath { get; set; }
public string Port { get; set; }
public string Prefix { get; set; }
}

view raw
UploadConfig.cs
hosted with ❤ by GitHub

We can then pass this object which will take data from an ini or config file to our Upload Class.

In the Upload class we have one public class SendFile. This creates the Session Options objects and calls a WINSCP put files operation.

using System;
using System.IO;
using log4net;
using WinSCP;
public class Upload
{
public static void SendFile(UploadConfig config, ILog log)
{
try
{
var sessionOptions = new SessionOptions
{
Protocol = config.Protocol == "FTP" ? Protocol.Ftp : Protocol.Sftp,
GiveUpSecurityAndAcceptAnySshHostKey = config.Protocol == "SFTP",
HostName = config.Host,
UserName = config.User,
Password = config.Password
};
if (!string.IsNullOrEmpty(config.PrivateKeyPath))
{
sessionOptions.SshPrivateKeyPath = config.PrivateKeyPath;
sessionOptions.PrivateKeyPassphrase = config.Password;
}
if (!string.IsNullOrEmpty(config.Port))
{
sessionOptions.PortNumber = int.Parse(config.Port);
}
var txOptions = new TransferOptions
{ResumeSupport = {State = TransferResumeSupportState.Off}};
using (var session = new Session())
{
session.Open(sessionOptions);
var remoteFile = CreateRemoteFile(
config.RemotePath,
config.ZipFileName);
log.DebugFormat("Starting transfer of {0} to {1}.",
config.ZipFileName, remoteFile);
var result = session.PutFiles(
config.ZipFileName,
remoteFile,
false,
txOptions);
log.DebugFormat("Transfer result: {0}. ",
result.IsSuccess);
}
}
catch (Exception e)
{
log.ErrorFormat("Error on Send: {0}", e.Message);
}
}
private static string CreateRemoteFile(string remotePath, string zipFile)
{
var remoteFile = string.Empty;
if (!string.IsNullOrWhiteSpace(remotePath)) remoteFile =
RemotePath.AddDirectorySeparator(remotePath.Trim());
remoteFile += Path.GetFileName(zipFile)?.Trim();
return remoteFile;
}
}

view raw
Upload.cs
hosted with ❤ by GitHub

Summary

We have used the WINSCP .Net library to create a simple application to automate zipping and uploading of files to an FTP site.

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 )

Google photo

You are commenting using your Google 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 )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.