Save file to ftp server - c#

I'm creating a file uploader in asp.net and c#.
I just wanted to save that uploaded files to ftp server directly.
Is it possible? And if it is possible, how can I set that ftp server authentication information.
(127.0.0.1 is just an example. I couldn't write my real ip. And I have to get files using HTTP protocol. Some of our clients ISPs don't support ftp. That's the main problem.)
protected void submit_button_Click(object sender, EventArgs e)
{
string filename = Path.GetFileName(upload_file.FileName);
string fileExt = Path.GetExtension(upload_file.FileName);
if (fileExt == ".csv")
{
string folder = Server.MapPath("ftp://127.0.0.1/uploads/");
upload_file.SaveAs(folder + "/" + filename);
ltr.Text = "Successful.";
}
else
{
upload_file.BorderColor = System.Drawing.Color.Red;
ltr.Text = "File type must be .csv.";
}
}

Its pretty simple.
The below method just pass in the file name. Obviously change the directory in the StreamReader.
EDIT: Sorry just noticed you said your client doesnt support FTP so the below wont work.
public bool ftpTransfer(string fileName)
{
try
{
string ftpAddress = "127.0.0.1";
string username = "user";
string password = "pass";
using (StreamReader stream = new StreamReader("C:\\" + fileName))
{
byte[] buffer = Encoding.Default.GetBytes(stream.ReadToEnd());
WebRequest request = WebRequest.Create("ftp://" + ftpAddress + "/" + "myfolder" + "/" + fileName);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
Stream reqStream = request.GetRequestStream();
reqStream.Write(buffer, 0, buffer.Length);
reqStream.Close();
}
return true;
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
return false;
}
}
Edit: Reworked the filename.

string filepath = "~/txtfile/";//this is folder name wher you want to save the file
HttpFileCollection uploadedFiles = HttpContext.Current.Request.Files;
for (int i = 0; i < uploadedFiles.Count; i++)
{
HttpPostedFile userPostedFile = uploadedFiles[i];
if (userPostedFile.ContentLength == 0)
{
continue;
}
userPostedFile.SaveAs(Server.MapPath(filepath) + userPostedFile.filename);
} //save file on the server

Related

Cannot make new directories in FTP (C#)

I was trying to upload a file to my FTP server (EC2) via a simple C# windows application I made.
Problem I'm Having : If the directory already exists, I can make a file inside it. However, if the directory doesn't exist, I cannot make a directory.
What I Checked : I double checked the write permissions. I logged in via WinSCP and I can make new directories in there without any problems. I've given the user privileges.
My Code :
private async void FileFTPUpload(string sourcefilepath, string folderPath) {
String ftpurl = #"ftp://xx.xxx.xxx.xxx/" + "trial/12/1.txt";
Console.WriteLine("Ftp url : " + ftpurl);
String ftpusername = "myUserName";
String ftppassword = "myPassword";
try {
string filename = Path.GetFileName(sourcefilepath);
string ftpfullpath = ftpurl;
WebRequest ftp = WebRequest.Create(ftpurl);
ftp.Method = WebRequestMethods.Ftp.MakeDirectory;
ftp.Credentials = new NetworkCredential(ftpusername, ftppassword);
ftp.Method = WebRequestMethods.Ftp.UploadFile;
FileStream fs = File.OpenRead(sourcefilepath);
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
Stream ftpstream = ftp.GetRequestStream();
ftpstream.Write(buffer, 0, buffer.Length);
ftpstream.Close();
} catch (Exception ex) {
Console.WriteLine("Exception Occurred : " + ex);
//throw ex;
}
}
Now, if the "trial/12/" exists, then 1.txt will be made. Otherwise, I get the error :
System.Net.WebException: The remote server returned an error: (553) File name not allowed.
I'm not sure what's happening and what's not. Could use some assistance.
Thank You.
EDIT : When I do this :
String ftpurl = #"ftp://xx.xxx.xxx.xxx/" + "trial";
It doesn't make a directory. I just makes a file named "trial".
Doing This :
String ftpurl = #"ftp://xx.xxx.xxx.xxx/" + "trial/";
Gives that same error 553
You will have to seperate your code into two requests. The first should create the directory and the second upload the file.
var filePath = #"ftp://xx.xxx.xxx.xxx/trial/12/1.txt";
var credentials = new NetworkCredential(ftpusername, ftppassword);
{
// create directory
var directoryPath = Path.GetDirectoryName(filePath);
var request = WebRequest.Create(directoryPath);
request.Method = WebRequestMethods.Ftp.MakeDirectory;
request.Credentials = credentials;
using(var response = (FtpWebResponse)requestDir.GetResponse())
{
// TODO: handle errors
}
}
{
// upload file
using (WebClient client = new WebClient())
{
client.Credentials = credentials;
client.UploadFile(filePath, "STOR", sourcefilepath);
}
}

Possible to temporarily store a file locally before sending to ftp server?

I've got an ASP control for file upload. When the user posts it, it's first locally stored on where I run the website and then I copy it to a remote ftp server.
However, is it possible to remove it from the local server once it's been copied to the ftp server? I'm thinking like storing it in a ~temp folder, but I can't get that to work. As of now I need to create a folder within my project called "temp". Any ideas? Here the method:
String id = Request.QueryString["ID"];
String path = Server.MapPath("~/temp/");
String filename = Path.GetFileName(fuPicture.PostedFile.FileName);
if (fuPicture.HasFile)
{
try
{
if (
fuPicture.PostedFile.ContentType == "image/jpeg" ||
fuPicture.PostedFile.ContentType == "image/png" ||
fuPicture.PostedFile.ContentType == "image/gif"
)
{
fuPicture.PostedFile.SaveAs(path + fuPicture.FileName);
}
else
{
lblFeedback.Text = "Not allowed file extension";
}
}
catch (Exception ex)
{
lblFeedback.Text = "Error when uploading";
}
path += fuPicture.FileName;
String ftpServer = "ftp://xxxx:xxxx";
String userName = "xx";
String password = "xx";
FtpWebRequest request =
(FtpWebRequest)WebRequest.Create(new Uri("ftp://xxxx:xxxx/" + id));
request.Method = WebRequestMethods.Ftp.MakeDirectory;
request.Credentials = new NetworkCredential(userName, password);
using (var resp = (FtpWebResponse)request.GetResponse())
{
WebClient client = new WebClient();
client.Credentials = new NetworkCredential(userName, password);
client.UploadFile(ftpServer + "/" + id + "/" +
new FileInfo(path).Name, "STOR", path);
}
You can call client.UploadData() to upload a byte array from memory, without involving your local disk at all.
Why you don't do a file.delete after the using statement?

Error while uploading a text file to FTP server C#

I am building a simple application that uploads a .txt file to a FTP server. I have done this before and i am using the same code as i used for the other application.
this is my code:
string localFilePath = #"\\fileprint\data\Groups\Operation\fileExports\dls\";
string archiveFilePath = #"\\fileprint\data\Groups\Operation\fileExports\dls\Archive\";
string logFilePath = #"C:\Users\lmy\Desktop\Logs";
string ftpServer = "ftp://server:21/home/out2233/tmp";
private string logFileName = "" + DateTime.Now.Year.ToString() + "-" + DateTime.Now.Month.ToString() + "-" + DateTime.Now.Day.ToString();
public void UploadFile()
{
try
{
string[] files = Directory.GetFiles(localFilePath);
foreach (string file in files)
{
string fileName = Path.GetFileName(file);
string modified = file.Remove(60, 6);
string modifiedFile = Path.GetFileName(modified);
FtpWebRequest ftpReq = (FtpWebRequest)FtpWebRequest.Create(new Uri(ftpServer + modifiedFile));
ftpReq.Method = WebRequestMethods.Ftp.UploadFile;
ftpReq.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
ftpReq.UsePassive = true;
ftpReq.UseBinary = true;
ftpReq.KeepAlive = true;
ftpReq.Credentials = new NetworkCredential("out2233", "password");
ftpReq.EnableSsl = true;
FileInfo fileInfo = new FileInfo(localFilePath + #"\" + fileName);
FileStream fileStream = fileInfo.OpenRead();
byte[] fileContent = new byte[fileInfo.Length];
fileStream.Read(fileContent, 0, Convert.ToInt32(fileInfo.Length));
Stream writer = ftpReq.GetRequestStream();
writer.Write(fileContent, 0, fileContent.Length);
fileStream.Close();
writer.Close();
FtpWebResponse response = (FtpWebResponse)ftpReq.GetResponse();
AppendLogFile(response, "Uploaded Files: ", fileName);
MoveToArchive(file, archiveFilePath + fileName);
}
}
catch (Exception exception)
{
Console.WriteLine(exception.Message);
}
}
But it get this error:
exception = {"Cannot send a content-body with this verb-type."}
when the code reaches this line:
Stream writer = ftpReq.GetRequestStream();
I have googled this but i can only find ASP examples. I cant seem to find out what i am doing wrong here. Hope you guys can help me.
thanks!
Looks like, you're trying to list ftp directory content, with this line:
ftpReq.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
(http://msdn.microsoft.com/en-us/library/system.net.webrequestmethods.ftp.listdirectorydetails%28v=vs.110%29.aspx)
Try removing it, leaving only this line:
ftpReq.Method = WebRequestMethods.Ftp.UploadFile;
http://msdn.microsoft.com/en-us/library/system.net.webrequestmethods.ftp.uploadfile%28v=vs.110%29.aspx

File Download from Ftp server with case insencitive match c#

Here is my code to download file from ftp server but it's case sensitive match.. could you please help me to download with out case match.
ex: if i'm trying to download "6Gt6hh.xml" but existing file in ftp sever is "6GT6hh.Xml". its not download with my code could you please help me.
private void Download(string file, ServerCredentials FtpCdrl, string DayOfYear, string dest, string ab)
{
try
{
string uri = "ftp://" + FtpCdrl.Host + "/" + FtpCdrl.DirPath.Replace("\\", "/") + "/" + DayOfYear + "/" + file;
Uri serverUri = new Uri(uri);
if (serverUri.Scheme != Uri.UriSchemeFtp)
{
return;
}
if (!Directory.Exists(dest))
Directory.CreateDirectory(dest);
if (!Directory.Exists(dest + "\\" + ab))
Directory.CreateDirectory(dest + "\\" + ab);
FtpWebRequest reqFTP;
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FtpCdrl.Host + "/" + FtpCdrl.DirPath.Replace("\\", "/") + "/" + DayOfYear + "/" + file));
reqFTP.Credentials = new NetworkCredential(FtpCdrl.UID, FtpCdrl.Pwd);
reqFTP.KeepAlive = false;
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.UseBinary = true;
reqFTP.Proxy = null;
reqFTP.UsePassive = false;
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream responseStream = response.GetResponseStream();
FileStream writeStream = new FileStream(dest + "\\" + ab + "\\" + file, FileMode.Create);
int Length = 2048;
Byte[] buffer = new Byte[Length];
int bytesRead = responseStream.Read(buffer, 0, Length);
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, Length);
}
status("File Downloaded Successfully: .\\" + ab + "\\" + file, Color.Green);
writeStream.Close();
response.Close();
failed = 0;
}
catch (WebException wEx)
{
failed++;
status("[Download Error]" + wEx.Message, Color.Red);
if (failed < 3)
Download(file, FtpCdrl, DayOfYear, dest, ab);
}
catch (Exception ex)
{
status("[Download Error]" + ex.Message, Color.Red);
}
}
public class ServerCredentials
{
public string Host, UID, Pwd, DirPath;
public int Pst;
public string Mail;
public string facility;
public string Batchextn;
public ServerCredentials(string _Host1, string _DirPath1, string _Uid1, string _Pwd1, string _Mail, int _Pst1, string _facility, string _batchextn)
{
Host = _Host1;
UID = _Uid1;
Pwd = _Pwd1;
DirPath = _DirPath1;
Pst = _Pst1;
Mail = _Mail;
facility = _facility;
Batchextn = _batchextn;
}
}
public List<ServerCredentials> Svr = new List<ServerCredentials>();
Uris are case sensetive and it is up to server to allow case insensetive acces to files. I.e. traditionally most HTTP servers ignore case in the path portion of Uri, but often respect case in Query portion.
In your case it looks like the FTP server you access enforces case match for file names (common for Unix/Linux servers) and may even have multiple files with different casing.
The correct implementation would be to list content first and than pick the file name from the list of files. The how to: List Directory Contents with FTP article covers this step.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://www.contoso.com/");
request.Credentials = new NetworkCredential ("anonymous","janeDoe#contoso.com");
request.Method = WebRequestMethods.Ftp.ListDirectoryDetails;
using(var response = (FtpWebResponse)request.GetResponse())
using(var responseStream = response.GetResponseStream())
using(var reader = new StreamReader(responseStream))
{
Console.WriteLine(reader.ReadToEnd());
}

Unable to rename file with ftp methods when current user directory is different from root

Remark: due to spam prevention mechanizm I was forced to replace the beginning of the Uris from ftp:// to ftp.
I've got following problem. I have to upload file with C# ftp method and afterwards rename it. Easy, right? :)
Ok, let's say my ftp host is like this:
ftp.contoso.com
and after logging in, current directory is set to:
users/name
So, what I'm trying to achieve is to log in, upload file to current directory as file.ext.tmp and after upload is successful, rename the file to file.ext
The whole difficulty is, as I guess, to properly set the request Uri for FtpWebRequest.
MSDN states:
The URI may be relative or absolute. If the URI is of the form "ftp://contoso.com/%2fpath" (%2f is an escaped '/'), then the URI is absolute, and the current directory is /path. If, however, the URI is of the form "ftp://contoso.com/path", first the .NET Framework logs into the FTP server (using the user name and password set by the Credentials property), then the current directory is set to UserLoginDirectory/path.
Ok, so I upload file with the following URI:
ftp.contoso.com/file.ext.tmp
Great, the file lands where I wanted it to be: in directory "users/name"
Now, I want to rename the file, so I create web request with following Uri:
ftp.contoso.com/file.ext.tmp
and specify rename to parameter as:
file.ext
and this gives me 550 error: file not found, no permissions, etc.
I traced this in Microsoft Network Monitor and it gave me:
Command: RNFR, Rename from
CommandParameter: /file.ext.tmp
Ftp: Response to Port 53724, '550 File /file.ext.tmp not found'
as if it was looking for the file in the root directory - not in the current directory.
I renamed the file manually using Total Commander and the only difference was that CommandParameter was without the first slash:
CommandParameter: file.ext.tmp
I'm able to successfully rename the file by supplying following absolute URI:
ftp.contoso.com/%2fusers/%2fname/file.ext.tmp
but I don't like this approach, since I would have to know the name of current user's directory. It can probably be done by using WebRequestMethods.Ftp.PrintWorkingDirectory, but it adds extra complexity (calling this method to retrieve directory name, then combining the paths to form proper URI).
What I don't understand is why the URI ftp.contoso.com/file.ext.tmp is good for upload and not for rename? Am I missing something here?
The project is set to .NET 4.0, coded in Visual Studio 2010.
Edit
Ok, I place code snippet.
Please note that ftp host, username and password should be filled out. For this sample to work - that is, produce an error - user directory must be different from root ("pwd"-command should return something different than "/")
class Program
{
private const string fileName = "test.ext";
private const string tempFileName = fileName + ".tmp";
private const string ftpHost = "127.0.0.1";
private const string ftpUserName = "anonymous";
private const string ftpPassword = "";
private const int bufferSize = 524288;
static void Main(string[] args)
{
try
{
string path = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);
if (!File.Exists(path))
File.WriteAllText(path, "FTP RENAME SAMPLE");
string requestUri = "ftp://" + ftpHost + "/" + tempFileName;
//upload
FtpWebRequest uploadRequest = (FtpWebRequest)WebRequest.Create(requestUri);
uploadRequest.UseBinary = true;
uploadRequest.UsePassive = true;
uploadRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
uploadRequest.KeepAlive = true;
uploadRequest.Method = WebRequestMethods.Ftp.UploadFile;
Stream requestStream = null;
FileStream localFileStream = null;
localFileStream = File.OpenRead(path);
requestStream = uploadRequest.GetRequestStream();
byte[] buffer = new byte[bufferSize];
int readCount = localFileStream.Read(buffer, 0, bufferSize);
long bytesSentCounter = 0;
while (readCount > 0)
{
requestStream.Write(buffer, 0, readCount);
bytesSentCounter += readCount;
readCount = localFileStream.Read(buffer, 0, bufferSize);
System.Threading.Thread.Sleep(100);
}
localFileStream.Close();
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)uploadRequest.GetResponse();
FtpStatusCode code = response.StatusCode;
string description = response.StatusDescription;
response.Close();
if (code == FtpStatusCode.ClosingData)
Console.WriteLine("File uploaded successfully");
//rename
FtpWebRequest renameRequest = (FtpWebRequest)WebRequest.Create(requestUri);
renameRequest.UseBinary = true;
renameRequest.UsePassive = true;
renameRequest.Credentials = new NetworkCredential(ftpUserName, ftpPassword);
renameRequest.KeepAlive = true;
renameRequest.Method = WebRequestMethods.Ftp.Rename;
renameRequest.RenameTo = fileName;
try
{
FtpWebResponse renameResponse = (FtpWebResponse)renameRequest.GetResponse();
Console.WriteLine("Rename OK, status code: {0}, rename status description: {1}", response.StatusCode, response.StatusDescription);
renameResponse.Close();
}
catch (WebException ex)
{
Console.WriteLine("Rename failed, status code: {0}, rename status description: {1}", ((FtpWebResponse)ex.Response).StatusCode,
((FtpWebResponse)ex.Response).StatusDescription);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
finally
{
Console.ReadKey();
}
}
}
I have encountered a similar issue. The problem is that FtpWebRequest (incorrectly) prepends '/' to rename requests, as can be seen from this log (upload & rename):
URL:
http://127.0.0.1/Test.txt
FTP log:
STOR Test.txt.part
RNFR /Test.txt.part
RNTO /Test.txt
Please note that this problem occurs only when you are uploading to the root directory. If you changed the URL to http://127.0.0.1/path/Test.txt, then everything would work fine.
My solution to this problem is to use %2E (dot) as the path:
URL:
http://127.0.0.1/%2E/Test.txt
FTP log:
STOR ./Test.txt.part
RNFR ./Test.txt.part
RNTO ./Test.txt
You have to url-encode the dot, otherwise FtpWebRequest would simplify the path "/./" to "/".
C#
using System.Net;
using System.IO;
Rename Filename on FTP Server function
C#
private void RenameFileName(string currentFilename, string newFilename)
{
FTPSettings.IP = "DOMAIN NAME";
FTPSettings.UserID = "USER ID";
FTPSettings.Password = "PASSWORD";
FtpWebRequest reqFTP = null;
Stream ftpStream = null ;
try
{
reqFTP = (FtpWebRequest)FtpWebRequest.Create(new Uri("ftp://" + FTPSettings.IP + "/" + currentFilename));
reqFTP.Method = WebRequestMethods.Ftp.Rename;
reqFTP.RenameTo = newFilename;
reqFTP.UseBinary = true;
reqFTP.Credentials = new NetworkCredential(FTPSettings.UserID, FTPSettings.Password);
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
ftpStream = response.GetResponseStream();
ftpStream.Close();
response.Close();
}
catch (Exception ex)
{
if (ftpStream != null)
{
ftpStream.Close();
ftpStream.Dispose();
}
throw new Exception(ex.Message.ToString());
}
}
public static class FTPSettings
{
public static string IP { get; set; }
public static string UserID { get; set; }
public static string Password { get; set; }
}

Categories