I need some guidance. I need to develop a customizable FTP in C# that should be configured using App.Config file. Also, the FTP should push the data to any server from any client again depends on config file.
I will appreciate if someone can guide, if there is any API or any other useful suggestion, or move me in the right direction.
You can use FtpWebRequest; however, this is fairly low level. There is a higher-level class WebClient, which requires much less code for many scenarios; however, it doesn't support FTP/SSL by default. Fortunately, you can make WebClient work with FTP/SSL by registering your own prefix:
private void RegisterFtps()
{
WebRequest.RegisterPrefix("ftps", new FtpsWebRequestCreator());
}
private sealed class FtpsWebRequestCreator : IWebRequestCreate
{
public WebRequest Create(Uri uri)
{
FtpWebRequest webRequest = (FtpWebRequest)WebRequest.Create(uri.AbsoluteUri.Remove(3, 1)); // Removes the "s" in "ftps://".
webRequest.EnableSsl = true;
return webRequest;
}
}
Once you do this, you can use WebClient almost like normal, except that your URIs start with "ftps://" instead of "ftp://". The one caveat is that you have to specify the method parameter, since there won't be a default one. E.g.
using (var webClient = new WebClient()) {
// Note here that the second parameter can't be null.
webClient.UploadFileAsync(uploadUri, WebRequestMethods.Ftp.UploadFile, fileName, state);
}
The accepted answer works, indeed. But I find it too cumbersome to register a prefix, implement an interface, and all that stuff, particularly, if you need it just for one transfer.
FtpWebRequest is not that difficult to use. So I believe that for one-time use, it's better to go this way:
FtpWebRequest request =
(FtpWebRequest)WebRequest.Create("ftp://ftp.example.com/remote/path/file.zip");
request.Credentials = new NetworkCredential("username", "password");
request.EnableSsl = true;
request.Method = WebRequestMethods.Ftp.UploadFile;
using (Stream fileStream = File.OpenRead(#"C:\local\path\file.zip"))
using (Stream ftpStream = request.GetRequestStream())
{
fileStream.CopyTo(ftpStream);
}
The key is the EnableSsl property.
For other scenarios, see:
Upload and download a binary file to/from FTP server in C#/.NET
We use edtFTPnet with good results.
Related
I am going through the example exam questions for Microsoft exam 70-483 "Programming in C#".
There is one question the answer to which I don't understand and couldn't find anything about the topic on the Internet.
The question is:
You are implementing a method named ProcessFile that retrieves data files from web servers and FTP servers. The ProcessFile() method has the following method signature:
Public void ProcessFile(Guid dataField, string dataFileUri)
Each time the ProcessFile() method is called, it must retrieve a unique data file and then save the data file to disk.
You need to complete the implementation of the
ProcessFile() method. Which code segment should you use?
FileWebRequest request = FileWebRequest.Create(dataFileUri) as FileWebRequest;
using (FileWebResponse response = request.GetResponse() as FileWebResponse)
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
using (StreamWriter writer = new StreamWriter(dataFieldId + ".dat"))
{
writer.Write(reader.ReadToEnd());
}
-or-
WebRequest request = WebRequest.Create(dataFileUri);
using (WebResponse response = request.GetResponse())
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
using (StreamWriter writer = new StreamWriter(dataFieldId + ".dat"))
{
writer.Write(reader.ReadToEnd());
}
According to the question-making people, the latter snippet, using "WebRequest" is the correct one. But I cannot figure out why the "FileWebRequest" one isn't.
Keep in mind the questions I am doing have been wrong a lot in the past, so maybe this isn't correct, either?
Some hours ago I also have met this question. Early I have not work with this, but by searching info in Google I concluded followings:
the main words in question is from web servers and FTP servers,
that means that dataFileUri may be like http://mywebserver or ftp://myftpserver
when you try to get file from ftp server, for example:
//from answer
var request1 = WebRequest.Create("ftp://myftpserver");
//from answer
var request2 = FileWebRequest.Create("ftp://myftpserver") as FileWebRequest;
var request3 = WebRequest.Create("ftp://myftpserver") as FtpWebRequest;
request1, request3 will have request value with type SystemNet.FtpWebRequest. request2 will be null.
The similar behavior will be when you try to use http://mywebserver: request2, request3 will be null.
when you use WebRequest the type of the request will be automatically detected by transfer protocol
So you don't need to think about whether file stored on web server/file server/ftp server
I'm trying to get my head around how to download a file from a secure FTP server from my AngularJS application using REST.
Thing is, that for security reasons, I can't just append an iframe or set window.location to ftp://myip:81/myfolder/myfile.pdf, so I have to find a way to trigger the download without this. My initial thought was to create a Generic handler which takes the filename and the folder name as parameters and then serve the file to the user through the context.Response somehow.
What I have so far is this:
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(path);
request.UsePassive = false;
request.Credentials = new NetworkCredential(ftpHelper.Username, ftpHelper.Password);
request.Method = WebRequestMethods.File.DownloadFile;
using (var response = (FtpWebResponse)request.GetResponse())
{
using (Stream responseStream = response.GetResponseStream())
{
// stuck here ...
}
}
request.Abort();
I've got a feeling that this isn't possible, though ;-) Can anyone confirm/disprove? And if it can be done, I'd love a small example/hint on this :-)
Thanks!
i'm trying to download a file from a link that doesn't contain the file, but instead it redirects to another (temporary) link that contains the actual file. The objective is to get an updated copy of the program without the need to open a browser. The link is:
http://www.bleepingcomputer.com/download/minitoolbox/dl/65/
I've tried to use WebClient, but it won't work:
private void Button1_Click(object sender, EventArgs e)
{
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
webClient.DownloadFileAsync(new Uri("http://www.bleepingcomputer.com/download/minitoolbox/dl/65/"), #"C:\Downloads\MiniToolBox.exe");
}
After searching and trying many things i've found this solution that involves using HttpWebRequest.AllowAutoRedirect.
Download file through code that has a redirect?
// Create a new HttpWebRequest Object to the mentioned URL.
HttpWebRequest myHttpWebRequest=(HttpWebRequest)WebRequest.Create("http://www.contoso.com");
myHttpWebRequest.MaximumAutomaticRedirections=1;
myHttpWebRequest.AllowAutoRedirect=true;
HttpWebResponse myHttpWebResponse=(HttpWebResponse)myHttpWebRequest.GetResponse();
It seems that's exactly what i'm looking for, but i simply don't know how to use it :/
I guess the link is a parameter of WebRequest.Create. But how can i retrieve the file to my directory? yes, i´m a noob... Thanks in advance for your help.
I switched from a WebClient based approach to a HttpWebRequest too because auto redirects didn't seem to be working with WebClient. I was using similar code to yours but could never get it to work, it never redirected to the actual file. Looking in Fiddler I could see I wasn't actually getting the final redirect.
Then I came across some code for a custom version of WebClient in this question:
class CustomWebclient: WebClient
{
[System.Security.SecuritySafeCritical]
public CustomWebclient(): base()
{
}
public CookieContainer cookieContainer = new CookieContainer();
protected override WebRequest GetWebRequest(Uri myAddress)
{
WebRequest request = base.GetWebRequest(myAddress);
if (request is HttpWebRequest)
{
(request as HttpWebRequest).CookieContainer = cookieContainer;
(request as HttpWebRequest).AllowAutoRedirect = true;
}
return request;
}
}
The key part in that code is AllowAutoRedirect = true, it's supposed to be on by default according to the documentation, which states:
AllowAutoRedirect is set to true in WebClient instances.
but that didn't seem to be the case when I was using it.
I also needed the CookieContainer part for this to work with the SharePoint external URLs we were trying to access.
I guess the easy option is simply this (after what you've got there.. and the URL you provided in place of http://www.contoso.com):
using (var responseStream = myHttpWebResponse.GetResponseStream()) {
using (var fileStream =
new FileStream(Path.Combine("folder_here", "filename_here"), FileMode.Create)) {
responseStream.CopyTo(fileStream);
}
}
EDIT:
In fact, this won't work. It isn't a HTTP redirect that downloads the file. Look at the source of that page.. you'll see this:
<meta http-equiv="refresh" content="3; url=http://download.bleepingcomputer.com/dl/1f92ae2ecf0ba549294300363e9e92a8/52ee41aa/windows/security/security-utilities/m/minitoolbox/MiniToolBox.exe">
It basically uses the browser to redirect. Unfortunately what you're trying to do won't work.
I'm trying to make a simple method to download a file from an FTP using FtpWebRequest with the method WebRequestMethods.Ftp.DownloadFile. The problem is that I wan't to display the progress of downloading and thus need to know the file size ahead to be able to calculate the percentage transfered. But when I call GetResponse in FtpWebRequest the ContentLength member is -1.
OK - so I get the size of the file in advance using the method WebRequestMethods.Ftp.GetFileSize. No problem. Then after getting the size I download the file.
This is where the problem in question appears...
After getting the size I try to reuse the FtpWebRequest and resets the method to WebRequestMethods.Ftp.DownloadFile. This causes an System.InvalidOperationException saying something like "Can't perform this action after sending the request." (may not be the exact formulation - translated from the one I get in Swedish).
I've found elsewhere that as long as I set the KeepAlive property to true, it doesn't matter, the connection is kept active. This is what I don't understand... The only object I've created is my FtpWebRequest object. And if I create another one, how can it know what connection to use? And what credentials?
Pseudo code:
Create FtpWebRequest
Set Method property to GetFileSize
Set KeepAlive property to true
Set Credentials property to new NetworkCredential(...)
Get FtpWebResponse from the request
Read and store ContentLength
Now I got the file size. So it's time to download the file. Setting Method now causes the exception mentioned above. So do I create a new FtpWebRequest? Or is there anyway to reset the request to be reused? (Closing the response made no difference.)
I don't understand how to move forward without re-creating the object. I could do that, but it just doesn't feel right. So i'm posting here in hope to find the correct way of doing this.
Here's the (non working) code (Inputs are sURI, sDiskName, sUser and sPwd.) :
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(sURI);
request.Method = WebRequestMethods.Ftp.GetFileSize;
request.Credentials = new NetworkCredential(sUser, sPwd);
request.UseBinary = true;
request.UsePassive = true;
request.KeepAlive = true;
FtpWebResponse resp = (FtpWebResponse)request.GetResponse();
int contLen = (int)resp.ContentLength;
resp.Close();
request.Method = WebRequestMethods.Ftp.DownloadFile;
resp = (FtpWebResponse)request.GetResponse();
Stream inStr = resp.GetResponseStream();
byte[] buff = new byte[16384];
sDiskName = Environment.ExpandEnvironmentVariables(sDiskName);
FileStream file = File.Create(sDiskName);
int readBytesCount;
int readTotal=0;
while ((readBytesCount = inStr.Read(buff, 0, buff.Length)) > 0)
{
readTotal += readBytesCount;
toolStripProgressBar1.Value = 100*readTotal/contLen;
Application.DoEvents();
file.Write(buff, 0, readBytesCount);
}
file.Close();
I hope someone can explain how this is supposed to work. Thanks in advance.
I don't think this will be answered so I'm "closing it" by telling you how I solved it.
Well, I didn't really solve it. I did however test the download by recreating the FtpWebRequest and noticed that on the FTP server it behaved as I wanted i.e. only one log on and then sequentially executing my requests.
This is how the code getting the file size and starting the download ended up:
// Start by fetching the file size
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(sURI);
request.Method = WebRequestMethods.Ftp.GetFileSize;
NetworkCredential nc = new NetworkCredential(sUser, sPwd);
request.Credentials = nc;
request.UseBinary = true;
request.UsePassive = true;
request.KeepAlive = true;
// Get the result (size)
FtpWebResponse resp = (FtpWebResponse)request.GetResponse();
Int64 contLen = resp.ContentLength;
// and now download the file
request = (FtpWebRequest)FtpWebRequest.Create(sURI);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = nc;
request.UseBinary = true;
request.UsePassive = true;
request.KeepAlive = true;
resp = (FtpWebResponse)request.GetResponse();
So no answer on if it's possible to reset the FtpWebRequest for re-use. But at least I know there's no redundant information being transferred.
Thanks to everybody who took an interest and spent time thinking of an answer.
FtpWebRequest can be used for only 1 request, like getting the file size or to download the file, but not both. You have to create 2 FtpWebRequests. Behind the scene, FtpWebRequest notices that it is the same URL and credentials and will reuse the same ftp connection without closing it, as long IsKeepAlieve is true, which is the default setting.
This is a sad example of bad design by Microsoft. Instead of letting us explicitly open and close a connection, they want to do it automatically for us and confuse everyone.
You're going to probably want to use the Async method. Here's the link to the MSDN doc.
http://msdn.microsoft.com/en-us/library/system.net.ftpwebrequest.aspx
GetResponseAsync()
That will keep your application from locking up too, so you won't have to use
Application.DoEvents();
You could also look at possibly using an alternative ftp library. imo the FtpWebRequest is not exactly the best ftp class. A quick search turned up this library. Ftp isn't stateless like HTTP. I prefer libraries that let you create a client, open a connect, and keep the connection alive.
http://sanity-free.org/dist/NullFX.Net-binary.zip
Here's the code exacmple I found
FtpClient client =
new FtpClient(
new IPEndPoint( IPAddress.Loopback, 21 ),
new NetworkCredential( "test", "testing#localdomain" )
);
client.Connect();
client.Download("testfile.zip", #"C:\downloads\testfile.zip");
The source is there too, so you would be able to possibly attach some events to the read process for your download progress tracking.
Does .NET (C#) have built in libraries for FTP? I don't need anything crazy... very simple.
I need to:
FTP into an account
Detect if the connection was refused
Obtain a text file
Delete the text file
What's the easiest way to do this?
Use the FtpWebRequest class, or the plain old WebClient class.
FTP into an account and retrieve a file:
WebClient request = new WebClient();
request.Credentials =
new NetworkCredential("anonymous", "janeDoe#contoso.com");
try
{
// serverUri here uses the FTP scheme ("ftp://").
byte[] newFileData = request.DownloadData(serverUri.ToString());
string fileString = Encoding.UTF8.GetString(newFileData);
}
catch (WebException ex)
{
// Detect and handle login failures etc here
}
Delete the file:
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(serverUri);
request.Method = WebRequestMethods.Ftp.DeleteFile;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Console.WriteLine("Delete status: {0}", response.StatusDescription);
response.Close();
(Code examples are from MSDN.)
This article implements a GUI for an FTP client using .NET 2.0 and has full source with examples.
Sample code includes connection, download and upload as well as good comments and explanations.
Just use the FtpWebRequest class. It already handles all the things you require.
Use System.Net.FtpWebRequest/FtpWebResponse
Use edtFTPnet, a free, open source .NET FTP library that will do everything you need.