Introduction
With the release of the new .NET 4.5 framework; I was pretty stoked at diving in and seeing all the new functionality available. One of the most talked about features was the improvements to the Asynchronous Programming model (previous versions used TPL). This is great, and will get used a lot by developers. But, one of the features I (and few others) were looking for was the support for sFTP built-in the .NET framework. Sadly, it was not found.
After some rigorous searching for a .NET wrapper to handle secure shell transmissions, I came across WinSCP; which is not only free (the best part!), but also included a wrapper to use in code. Jackpot!
Using WinSCP is really straightforward. The developer has done an excellent job in documenting, an active community of users, and really just putting together a tool that interfaces well with .NET.
Background
Some knowledge might be helpful on how currently .NET handles FTP and a quick read on FtpWebRequest and FtpWebResponse would be helpful, but not necessary.
Remember, there are a number of ways to transfer files using FTP and sFTP. But this particular scenario needed to transfer files via code (C#). Oh, and as an aside, the 's' in front of 'sFTP' does not mean 'secure' (literally), but instead stands for 'SSH' - secure shell.
Another note, in order to use WinSCP, you will need the SSHHostKeyFingerprint
for the designated server you are trying to connect to. If you are not sure about how to obtain this, you can always ask your administrator for this key. This key is not top secret information and should be available to you publicly.
Or, similarly, you could install a FTP client that also handles SSH transmissions and grab the SSH Host Key Fingerprint via the options menu for the tools that have been tested below:
For WS_FTP:
- Download and install WS_FTP (trial version will work as well).
- Connect to your sFTP site via the hostname, username, and password.
- When prompted to examine the "Untrusted SSH Host Key", select "Trust this key"
- If you ever need to recover the SSH Host Key, you can go to Tools -> Options -> SSH (On the left) -> Trusted Hosts
For WinSCP:
- Download and install WinSCP.
- Connect to your sFTP site using your hostname, username, and password.
- Once connected, you can retrieve the SSH host key fingerprint by going into "Commands" -> "Server/Protocol Information". You should see the SSH Host Key Fingerprint in the "Protocol" tab.
For FileZilla:
- Download and install Filezilla.
- Connect to your sFTP using your hostname, username, and password
- Once you're connected, you'll be prompted to accept the SSH Host Key. At this point, I would get a screen shot of the SSH Host Key or write it down. Once you get past the SSH Key pop-up and haven't copied this key, it's going to be a challenge to get that key out of FileZilla. This is because FileZilla uses a adapted PuTTY component for sFTP support. FileZilla and PuTTY share the host key cache.
- Here's a way to get the host key out of FileZilla (it's long and involves the registry).
If you get 'click happy', you're likely to miss the dialog and will probably need to re-install FileZilla (with some registry magic) to review the key again. So, read the prompts that you're being asked to click through :-).
That was longer than intended...now charge forward...
Using the Code
Now the best part! Go here to grab the WinSCP assembly. We're assuming that you are well versed in Visual Studio project files and how to add, remove, compile, and build projects.
There will be two files in the .NET assembly WinSCP download. One will be the actual assembly itself (WinSCPnet.dll) and the second file will be the executable, WinSCP.exe.
Add both of these files to your Visual Studio project output folder; which should be the /obj/debug folder. For simplicity sake, the files WinSCPnet.dll and WinSCp.exe should be copied into the output folder for this scenario. If you want to use a different folder, then you can set the "Session.ExecutablePath
" property of the WinSCP API to tell the assembly to look in a different folder other than the output path. A more detailed instruction list is available here at the WinSCP site.
In our scenario, we were going to be doing two functions:
- Get the files off of a sFTP site, or
- Put the files on an sFTP site.
The code is going be really similar for both of these actions.
Get Files (pull down from sFTP - Download)
using WinSCP; ...
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = ftpServerName, UserName = ftpUser,
Password = ftpPwd,
PortNumber = 22,
SshHostKeyFingerprint = "ssh - rsa //followed by your 16 bit key"
};
using (Session session = new Session())
{
session.SessionLogPath = "your log path";
Session.Open(sessionOptions); TransferOptions transferOptions = new TransferOptions();
transferOptions.TransferMode = TransferMode.Binary; transferOptions.FilePermissions = null; transferOptions.PreserveTimestamp = false; transferOptions.ResmeSupport.State = TransferResumeSupportState.Off;
TransferOperationalResult transferResult;
transferResult = session.GetFiles("/" + filenameToGet, PathToPlaceFile, false, transferOptions;
transferResult.Check()
}
Put Files (Send FTP Files - Upload)
using WinSCP; ...
SessionOptions sessionOptions = new SessionOptions
{
Protocol = Protocol.Sftp,
HostName = ftpServerName, UserName = ftpUser,
Password = ftpPwd,
PortNumber = 22,
SshHostKeyFingerprint = "ssh - rsa //followed by your 16 bit key"
};
using (Session session = new Session())
{
session.SessionLogPath = "your log path";
Session.Open(sessionOptions); TransferOptions transferOptions = new TransferOptions();
transferOptions.TransferMode = TransferMode.Binary; transferOptions.FilePermissions = null; transferOptions.PreserveTimestamp = false; transferOptions.ResmeSupport.State = TransferResumeSupportState.Off;
TransferOperationalResult transferResult;
transferResult = session.PutFiles(localPathWithFilename, RemotePath, false, transferOptions;
transferResult.Check()
}
The WinSCP site has GREAT documentation on all the methods covered above and examples (C# and VB.NET) can be found here. The attempt here is to make it all concise and just get the sFTP transfer working quickly.
Points of Interest
Do keep in mind that sFTP is not the same as FTPS. sFTP is 'secure shell' and FTPs is SSL over FTP - totally two different concepts. A simple search will get you tons of information.
The WinSCP .NET wrapper has been nothing short of a life saver. There are other solutions out there (Granados, SharpSSH, etc.) and find one that works for you. Here is a discussion on sFTP libraries that you could use from stackoverflow.com.
Hope that this helps and corrections are welcome!
History
- 6th May, 2014: Initial version