C
C#2y ago
uselessxp

❔ recommended FTP library/nuget?

Well, I need to to a task via FTP: - if exist delete a folder with its content - upload a folder with its files I'm trying to to that using FtpWebRequest Class but it seems that's a bit limited, I'm still reading MSDocs and it seems that I can't delete a folder recursively, so I get the error "folder is not empty" when trying to delete
75 Replies
uselessxp
uselessxpOP2y ago
the RemoveDirectory method seems to not have much in
uselessxp
uselessxpOP2y ago
so I thought to try the most used FTP nuget, what do you think about?
Pobiega
Pobiega2y ago
GitHub
GitHub - robinrodricks/FluentFTP: An FTP and FTPS client for .NET &...
An FTP and FTPS client for .NET & .NET Standard, optimized for speed. Provides extensive FTP commands, File uploads/downloads, SSL/TLS connections, Automatic directory listing parsing, File...
Joch
Joch2y ago
Yes i also using this fluent ftp
uselessxp
uselessxpOP2y ago
ok so I'll go for it 😎
uselessxp
uselessxpOP2y ago
is there some documentation? I'm reading the github one, but i was unable to find an order that explain the basics. reading this: https://github.com/robinrodricks/FluentFTP/wiki/Class-FtpClient-DeleteDirectory I was able to write this, I think I did it well, but shouldn't be a part that explain the beginning, I mean the connection with credentials and parameters definition?
var test = new FtpClient();
test.DeleteDirectory("ftp://127.0.0.1/myfolder", FtpListOption.Recursive);
var test = new FtpClient();
test.DeleteDirectory("ftp://127.0.0.1/myfolder", FtpListOption.Recursive);
GitHub
Class FtpClient DeleteDirectory
An FTP and FTPS client for .NET & .NET Standard, optimized for speed. Provides extensive FTP commands, File uploads/downloads, SSL/TLS connections, Automatic directory listing parsing, File...
uselessxp
uselessxpOP2y ago
I found a sort of index, it seems good, so I'm editing the code like this 🤞
var test = new FtpClient();
test.Host = "127.0.0.1";
test.Port = 21;
test.DeleteDirectory("ftp://127.0.0.1/myfolder", FtpListOption.Recursive);
var test = new FtpClient();
test.Host = "127.0.0.1";
test.Port = 21;
test.DeleteDirectory("ftp://127.0.0.1/myfolder", FtpListOption.Recursive);
uselessxp
uselessxpOP2y ago
it's awesome I could also put a custom command to execute 😎
Joch
Joch2y ago
I think you can use this. var client = new AsyncFtpClient("123.123.123.123", "david", "pass123"); await client.AutoConnect(); await client.DeleteDirectory("/htdocs/extras/")
uselessxp
uselessxpOP2y ago
well I setted it all, the only thing on which I'm stuck is credentials definition, should I use tuple? oh, nice form, I can include parameters directly into it. I seen this autoconnect but I skipped it since idk how does it act, now I try do you recommend Async? isn't missing recursive parameter on deletedirectory?
Joch
Joch2y ago
The autoconect something like connect to ftp. In their previous version it was connect only, after i update to latest it now autoconnect. Yes i recommend it but if your ftp will be use with many users. If not you may use the synchronous. About recursive you may add it as 2nd parameters in delete directory
uselessxp
uselessxpOP2y ago
oh, just found the usage
uselessxp
uselessxpOP2y ago
yeah I have to familiarise with async in general btw since I never used it regarding the connection, I wrote the code in this way
var test = new FtpClient();
test.Host = "127.0.0.1";
test.Port = 21;
test.Credentials = new NetworkCredential("admin", "password");
test.Connect();
test.DeleteDirectory("ftp://127.0.0.1/myfolder", FtpListOption.Recursive);
test.Disconnect();
var test = new FtpClient();
test.Host = "127.0.0.1";
test.Port = 21;
test.Credentials = new NetworkCredential("admin", "password");
test.Connect();
test.DeleteDirectory("ftp://127.0.0.1/myfolder", FtpListOption.Recursive);
test.Disconnect();
if I use autoconnect does it know when to disconnect?
Joch
Joch2y ago
You need to disconnect the ftp, after your needs
uselessxp
uselessxpOP2y ago
yeah I wrote a disconnet(); at the end, just tested my code and it works perfect and very very fast, awesome^^ much better than MS thing in my case I used .Connect() and .Disconnect() so I'm doing all my self, which is so the purpose of AutoConnect() ? very important question, do you think that deleting a folder with DeleteDirectory() and reuploading the same folder could cause timing problems? example:
var test = new FtpClient();
test.Host = "127.0.0.1";
test.Port = 21;
test.Credentials = new NetworkCredential("admin", "password");
test.Connect();
test.DeleteDirectory("ftp://127.0.0.1/myfolder", FtpListOption.Recursive);
test.UploadDirectory(asasdassad) //I write in pseudocode still didn't look how to do it
test.Disconnect();
var test = new FtpClient();
test.Host = "127.0.0.1";
test.Port = 21;
test.Credentials = new NetworkCredential("admin", "password");
test.Connect();
test.DeleteDirectory("ftp://127.0.0.1/myfolder", FtpListOption.Recursive);
test.UploadDirectory(asasdassad) //I write in pseudocode still didn't look how to do it
test.Disconnect();
hypnotising the DeleteDirectory need 2 minutes for delete all, will the UploadDirectory start after 2 mins or it just launch bot commands like when you do ProcessStart without putting .WaitForExit() ?
uselessxp
uselessxpOP2y ago
really I can upload with this Mirror that automatically delete additional files o_O this library is awesome^^ I think I'll still delete and normal upload since I retain that it take less time
x0rld 👻 🎃
you can use the property initialization with that syntax
new FtpClient()
{
Host = "127.0.0.1",
Port = 21,
Credentials = new NetworkCredential("admin", "password"),
}
new FtpClient()
{
Host = "127.0.0.1",
Port = 21,
Credentials = new NetworkCredential("admin", "password"),
}
uselessxp
uselessxpOP2y ago
oh, really prettier than mine, also if I don't understand yet when and how to do this
Pobiega
Pobiega2y ago
also, just to be clear: https://github.com/robinrodricks/FluentFTP/wiki/Quick-Start-Example this was 1 click away at all times :p
uselessxp
uselessxpOP2y ago
actually it works good, just one not serious problem, I can get when trying delete a folder using https://github.com/robinrodricks/FluentFTP/wiki/Class-FtpClient-DeleteDirectory
ftpClient.DeleteDirectory("myfolder", FtpListOption.Recursive);
ftpClient.DeleteDirectory("myfolder", FtpListOption.Recursive);
if the folder does not exist I get this FluentFTP.Exceptions.FtpCommandException: 'Code: 550 Message: Directory not found' now I searched into documentation but It seems there's no option to handle this, so it is correct if I use try-catch statement for handle this exception?
GitHub
Class FtpClient DeleteDirectory
An FTP and FTPS client for .NET & .NET Standard, optimized for speed. Provides extensive FTP commands, File uploads/downloads, SSL/TLS connections, Automatic directory listing parsing, File...
Pobiega
Pobiega2y ago
or jsut check if the directory exists before trying to delete it?
uselessxp
uselessxpOP2y ago
good idea^^ I thought it was implemented in the delete method by the author
Pobiega
Pobiega2y ago
no, that would break SRP
uselessxp
uselessxpOP2y ago
SRP?
Pobiega
Pobiega2y ago
single responsibility principle a delete command should just delete, and if it cant, its reasonable to throw an exception if it always checked for existance before deleting, it would be doing two things - and that would be less flexible there are times you know the file/directory exists and dont care about checking after all, its trivial to add them together, you could probably even make an extension method to do so, should you wish
uselessxp
uselessxpOP2y ago
oh, it make sense, so the author should remember to include a directory exist method
uselessxp
uselessxpOP2y ago
yeah I implemented but I have a generic doubt
if (!ftpClient.DirectoryExists("myfolder"))
{
Console.WriteLine("Directory does not exist, skipping . . .");
}
else ftpClient.DeleteDirectory("myfolder", FtpListOption.Recursive);
if (!ftpClient.DirectoryExists("myfolder"))
{
Console.WriteLine("Directory does not exist, skipping . . .");
}
else ftpClient.DeleteDirectory("myfolder", FtpListOption.Recursive);
if (!ftpClient.DirectoryExists("myfolder"))
{
Console.WriteLine("Directory does not exist, skipping . . .");
}
else if (ftpClient.DirectoryExists("myfolder")) ftpClient.DeleteDirectory("myfolder", FtpListOption.Recursive);
if (!ftpClient.DirectoryExists("myfolder"))
{
Console.WriteLine("Directory does not exist, skipping . . .");
}
else if (ftpClient.DirectoryExists("myfolder")) ftpClient.DeleteDirectory("myfolder", FtpListOption.Recursive);
do you think is more correct else or an else if?
Pobiega
Pobiega2y ago
public static class FtpClientExtensions
{
public static void DeleteDirectoryIfExists(this FtpClient client, string path, FtpListOption option)
{
if (client.DirectoryExists(path))
{
client.DeleteDirectory(path, option);
}
}
}
public static class FtpClientExtensions
{
public static void DeleteDirectoryIfExists(this FtpClient client, string path, FtpListOption option)
{
if (client.DirectoryExists(path))
{
client.DeleteDirectory(path, option);
}
}
}
is what I would do. you could have this return a bool indicating if the folder was deleted or not, if you really need that printout
uselessxp
uselessxpOP2y ago
wow, you pass FtpClient also as parameter
Pobiega
Pobiega2y ago
its an extension method you would call it as normal ftpClient.DeleteDirectoryIfExists("myfolder", FtpListOption.Recursive);
uselessxp
uselessxpOP2y ago
ok
Tvde1
Tvde12y ago
btw use SFTP not FTP as it is insecure
uselessxp
uselessxpOP2y ago
yeah the final target will be SFTP but I was unable to set it on my xampp so I started with FTP
uselessxp
uselessxpOP2y ago
don't tell me that I can't use it with FluentFTP
Pobiega
Pobiega2y ago
You can't. FTPS, sure, but SFTP is a different beast.
uselessxp
uselessxpOP2y ago
hm so in SFTP case I can't use this nuget, right?
Pobiega
Pobiega2y ago
correct
uselessxp
uselessxpOP2y ago
:/ it was so awesome^^ lets try this SSH.NET, it seems quite similar is there an easy way to create/simulate a local SFTP and SSH? I created the normal one with XAMPP tools that include FileZilla Server
Pobiega
Pobiega2y ago
do you have docker installed? could just spin up a fairly bog-standard linux image
Florian Voß
Florian Voß2y ago
I would disagree that this breaks SRP. Think about all the Try methods, whether it is TryParse(), TryAdd() or any other. They check if its possible but they also perform the actual operation. Does that break SRP? I don't think it does
Pobiega
Pobiega2y ago
Well this isn't TryDeleteDirectory Try methods are expected to "try"
Florian Voß
Florian Voß2y ago
thats right, I'm just saying every method can contain validation and that shouldn't be seen as a responsibility unless the validation really is the responsibility if that makes sense. If you're writing a method for validation then of course it's only responsibility should be validation and nothing else but if the responsibility is something else other than validation than having some validation in it doesn't add a second responsiblity to it, does it?
Pobiega
Pobiega2y ago
I suppose you could argue its not SRP but more... composability? since each operation performed in FTP has a roundtrip associated with it, its certainly not free to check if a directory exists or not so if you need that behaviour, its fairly easy to compose it yourself, as I showed above but its good that it doesnt by default
Florian Voß
Florian Voß2y ago
yeah I agree just wanted to make sure that if we write a method ourselves called ´WriteToFile´ then checking first if there already is such file doesn't break SRP. But agreeing with everything else you've said
Pobiega
Pobiega2y ago
Not sure I entirely agree for that case. If its part of a larger responsiblity, thats fine. "This method is responsible for saving my application data to a file." but if its a generic WriteToFile, then suddenly that changes things Like, where do you draw the line for what should throw exceptions and what should the method handle for you? File.WriteAllText for example will create the file if it doesnt exist, otherwise open and overwrite. it will however throw exceptions if the path isnt writable, or if it failed to secure a file handle Makes sense, since this is supposed to be the "easy to use" method. it should do what is feasible but if it can't, then it seems appropriate to throw exceptions so yeah, it might be fine to validate, it all depends on the purpose and how generic or not it is. imo.
Florian Voß
Florian Voß2y ago
thats a good summary 🙂
uselessxp
uselessxpOP2y ago
no I did it with virtualbox, but I'll try one day, I heard this docker use very low resources I'm making initial tests with SSH.NET and for try I just setted up a command that create a blank file for see if it successfully connect and act on the server. So I wrote this code, the .txt file is created, but the console for some reason is stuck on "Using SSH . . ."
Console.WriteLine("\nUsing SSH . . .");
using (var client = new SshClient(serverAddress, "admin2", "password123"))
{
client.Connect();
client.RunCommand("cat > byDotNet.txt");
client.Disconnect();
}
Console.WriteLine("\nWorks!!!");
Console.WriteLine("\nUsing SSH . . .");
using (var client = new SshClient(serverAddress, "admin2", "password123"))
{
client.Connect();
client.RunCommand("cat > byDotNet.txt");
client.Disconnect();
}
Console.WriteLine("\nWorks!!!");
edit: just tried to manually do it via PuTTy, and the result is the same, after I write "cat > file.txt" I'm no able to go on or type further commands till I press CTRL+C, what could be? ok it seems it's a particular of "cat" command, I just tried to deleting a dir and it works
Pobiega
Pobiega2y ago
cat prints from a stream to the console you gave it no arguments, so its reading from STDIN if you just wanted to make a file, you use echo hello > bydotnet.txt or simpler, touch bydotnet.txt
uselessxp
uselessxpOP2y ago
oh, ok now I'm replicating the old function FluentFTP into SSH.NET
if (!ftpClient.DirectoryExists("myfolder")) Console.WriteLine("Directory does not exist, skipping . . .");
else ftpClient.DeleteDirectory("myfolder", FtpListOption.Recursive);
if (!ftpClient.DirectoryExists("myfolder")) Console.WriteLine("Directory does not exist, skipping . . .");
else ftpClient.DeleteDirectory("myfolder", FtpListOption.Recursive);
it seems deleting folder and content don't need any check, it works in any case this code:
client.RunCommand("rm -rf myfolder");
client.RunCommand("rm -rf myfolder");
the only complicated thing seems the folder upload, old code is
Console.WriteLine("Uploading files . . .");
ftpClient.UploadDirectory(uploadPath, ".", FtpFolderSyncMode.Update, FtpRemoteExists.Overwrite, verifyOptions: FtpVerify.Retry);
Console.WriteLine("Uploading complete!");
Console.WriteLine("Uploading files . . .");
ftpClient.UploadDirectory(uploadPath, ".", FtpFolderSyncMode.Update, FtpRemoteExists.Overwrite, verifyOptions: FtpVerify.Retry);
Console.WriteLine("Uploading complete!");
about the new code currently I still don't know how to proceed, I downloaded the documentation of this SSH.NET but is in .chm extension, and it seems text is not loading, so I'm trying to convert it in PDF
Pobiega
Pobiega2y ago
public class SftpClient : BaseClient, ISftpClient this seems promising
var connectionInfo = new ConnectionInfo("sftp.foo.com",
"guest",
new PasswordAuthenticationMethod("guest", "pwd"),
new PrivateKeyAuthenticationMethod("rsa.key"));
using (var client = new SftpClient(connectionInfo))
{
client.Connect();
}
var connectionInfo = new ConnectionInfo("sftp.foo.com",
"guest",
new PasswordAuthenticationMethod("guest", "pwd"),
new PrivateKeyAuthenticationMethod("rsa.key"));
using (var client = new SftpClient(connectionInfo))
{
client.Connect();
}
Florian Voß
Florian Voß2y ago
It can do more than that tho. The way he uses it with cat > filename.txt it should open a stream from the console to the file. After that you can insert text in the console that gets written directly into the file. So missing arguments can’t be the reason why it’s not working, whatever else may be the reason
Pobiega
Pobiega2y ago
... if you open up a shell right now and type cat > filename.txt you can answer that question yourself
uselessxp
uselessxpOP2y ago
rsa?
Pobiega
Pobiega2y ago
it prints from a stream to an output, usually STDOUT. In this case, that output is redirected to a file you can log in however you want, of course you dont have to use pkey auth
uselessxp
uselessxpOP2y ago
what does it do? I know what rsa is, but idk what does it do, is a security setting?
Pobiega
Pobiega2y ago
yes its a different way of authenticating, aka proving an identity
uselessxp
uselessxpOP2y ago
so it generate automatically this rsa.key
Pobiega
Pobiega2y ago
no its logging in using private key authentication I'm guessing the ConnectionInfo ctor takes in a params IAuthenticationMethod[] and it tries them in order
Florian Voß
Florian Voß2y ago
what question can I answer myself? I didn't ask a question when
Pobiega
Pobiega2y ago
So missing arguments can’t be the reason why it’s not working, whatever else may be the reason
that command, cat > filename.txt, redirects stdin on a normal term, you'd press CTRL+D or whatever you have bound to that to stop the stream, which lets cat write the file, flush, and terminate
Florian Voß
Florian Voß2y ago
ahhh now I understand, ty
uselessxp
uselessxpOP2y ago
am I doing something wrong?
Pobiega
Pobiega2y ago
yes your client is of type SshClient you need an SftpClient
uselessxp
uselessxpOP2y ago
oh, my bad :/ SshClient and SftpClient are interfaces, right?
Pobiega
Pobiega2y ago
nope. ISftpClient is an interface SftpClient is a class implementing said interface
uselessxp
uselessxpOP2y ago
ok
uselessxp
uselessxpOP2y ago
well, there is no trace of "folder"/"directory", and if I Ctrl+F on the guide with "recurs" I get 0 results, guessing I can't upload folders with their content should I switch to WinSCP?
Pobiega
Pobiega2y ago
winSCP is an excellent client, its what I use myself but i have never tried automating it
uselessxp
uselessxpOP2y ago
as I read online its nuget pack allow SSH connections and Folder uploads
uselessxp
uselessxpOP2y ago
or maybe not, someone here wrote a function that theoretically should do the job https://stackoverflow.com/questions/39397746/ssh-net-upload-whole-folder I'm reading for understand better what does this cycle do
Stack Overflow
SSH.NET Upload whole folder
I use SSH.NET in C# 2015. With this method I can upload a file to my SFTP server. public void upload() { const int port = 22; const string host = "**"; const string username = "...
uselessxp
uselessxpOP2y ago
idk in this sample there's a function that call itself 🧐
Pobiega
Pobiega2y ago
yes? you know what thats called? its called a recursive function and you are trying to do a recursive folder upload, no?
uselessxp
uselessxpOP2y ago
yes it works very well but I'll try to understand the process, also I have to understand where put the .Connect(); for test I just putted it randomly into the function using a rough trycatch for avoiding the error "already connected", but if I'm not wrong, the correct form should be
using (var sftpClient = new SftpClient(serverAddress, sshUser, sshPassword))
{
sftpClient.Connect();
UploadDirectory(new SftpClient(serverAddress, sshUser, sshPassword), uploadPath, "myfolder");
sftpClient.Disconnect();
}
using (var sftpClient = new SftpClient(serverAddress, sshUser, sshPassword))
{
sftpClient.Connect();
UploadDirectory(new SftpClient(serverAddress, sshUser, sshPassword), uploadPath, "myfolder");
sftpClient.Disconnect();
}
oh, maybe I can pass sftpClient instead of instantiating a new one ok it works very very well, last little problem is that he expect all the folders and subfolder already exist in the destination, or it throw up this Renci.SshNet.Common.SftpPathNotFoundException: 'No such file' if I could mix sshClient and sftpClient I could just create the folder when it does not exist through sshClient commands 🦊 but I think it's not possible so I'll try to edit this sshClient.RunCommand("rm -rf myfolder"); in order to make it only empty the folder from files hoping it will leave subfolders or maybe none of them, I get error on sftpClient.CreateDirectory(subPath); so it provide a folder creation method, I think the main problem is that the root folder is previously deleted by me, if so I can solve easily
Accord
Accord2y ago
Was this issue resolved? If so, run /close - otherwise I will mark this as stale and this post will be archived until there is new activity.
Want results from more Discord servers?
Add your server