Currently I'm writing a specific program, and one of it fuctions is download/upload files via ftp protocol. I made a method for upload, but when I calls it second time, my program freezes (and after 100 seconds it shows me an timeout error).
Method:
public static void uploadFile(string FTPAddress, string filePath, string username, string password)
{
try
{
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(FTPAddress + "/" + filePath);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
FileStream stream = File.OpenRead(filePath);
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
stream.Flush();
stream.Dispose();
using (Stream reqStream = request.GetRequestStream())
{
reqStream.Write(buffer, 0, buffer.Length);
reqStream.Flush();
reqStream.Dispose();
}
request.Abort();
MessageBox.Show("Uploaded Successfully");
}
catch (Exception e)
{
if (MessageBox.Show("Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error) == DialogResult.Cancel)
{
Application.Exit();
}
else
FTPTools.uploadFile({calls this function again (it doesn't matter)});
}
}
I call it when pushing the button:
Application.DoEvents();
FTPTools.uploadFile({my ftp address}, {filename}, {login}, {password});
By using Visual Studio Debugger I've found that freeze happens when
Stream reqStream = request.GetRequestStream()
calls. Now I don't have any ideas how to fix it. Maybe someone there would solve my problem.
UPDATED 11/11/2016:
Network trace log
UPDATED 12/11/2016:
Today I little updated my code, but it doesn't helped me:
public static void uploadFile(string FTPAddress, string filePath, string username, string password)
{
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(FTPAddress + "/" + filePath);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
request.Proxy = null;
request.Timeout = 5000;
request.ServicePoint.ConnectionLeaseTimeout = 5000;
request.ServicePoint.MaxIdleTime = 5000;
try
{
using (FileStream stream = File.OpenRead(filePath))
{
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
stream.Close();
using (Stream reqStream = request.GetRequestStream())
{
reqStream.Write(buffer, 0, buffer.Length);
reqStream.Close();
}
using (FtpWebResponse resp = (FtpWebResponse)request.GetResponse())
{
resp.Close();
}
request.Abort();
}
MessageBox.Show("Uploaded Successfully");
}
catch (Exception e)
{
if (MessageBox.Show("Error", MessageBoxButtons.RetryCancel, MessageBoxIcon.Error) == DialogResult.Cancel)
{
Application.Exit();
}
else
FTPTools.uploadFile({calls this function again (it doesn't matter)});
}
finally
{
request.Abort();
}
}
UPDATED 12/12/2016
Today I've found an anomaly with my code: when I call this method (that uploads file) from a method with if/else statements, it gots time-outed at second call. But when I call this method (that uploads file) from a method without if/else statements, it works correctly at every call. I have no idea why it happens, but I cannot call my method without if/else statements.
For example, this code works correctly if I call 'upl()' method:
public void upl()
{
FTPTools.uploadFile(address, fileName, username, password);
}
And this code throws a time-out exception at second call if I call 'checker()' method:
public void upl()
{
FTPTools.uploadFile(address, fileName, username, password);
}
public void checker()
{
int a = 0, b = 0;
if (a == b)
upl();
}
Related
I wonder if this FtpWebRequest goes wrong and, it goes to the catch event. I have seen an example code where they posted what I have uncommented in the catch event, - to clean up the resources.
But I don't know what is the proper way to do that in this scenario? Should I just put all of those to: = null; or is this wrong to do? What is the proper way to do it?
cleanUp(sourceStream, ref response, ref requestStream, ref request);
void uploadimage()
{
String sourceimage = "C:/ESD/image_2.jpg";
Task<bool> task = FtpUploadFile(sourceimage);
if (task.IsFaulted == false)
{
MessageBox.Show(task.Result.ToString());
}
}
private Task closeRequestStreamAsync(Stream requestStream) { return Task.Run(() => { requestStream.Close(); }); }
public async Task<bool> FtpUploadFile(string filename)
{
//if exception occurs we want to be able to close these
FtpWebResponse response = null;
FtpWebRequest request = null;
FileStream sourceStream = null;
Stream requestStream = null;
try
{
bool isimage = false; String ext = Path.GetExtension(filename);
if (ext == ".jpg" || ext == ".jpeg" || ext == ".png" || ext == ".gif" || ext == ".bmp") { isimage = true; }
request = (FtpWebRequest)WebRequest.Create("ftp://someurl.com/Folder1/test1.jpg");
request.UsePassive = true;
if (isimage == true) { request.UseBinary = true; } //for images
if (isimage == false) { request.UseBinary = false; } //for text
request.KeepAlive = true; //keep the connection open
request.Method = WebRequestMethods.Ftp.UploadFile;
request.ConnectionGroupName = "Group1";
request.ServicePoint.ConnectionLimit = 4;
//These are the credentials.
request.Credentials = new NetworkCredential("username", "password");
sourceStream = File.OpenRead(filename);
byte[] buffer = new byte[sourceStream.Length];
await sourceStream.ReadAsync(buffer, 0, buffer.Length);
sourceStream.Close();
requestStream = await request.GetRequestStreamAsync();
await requestStream.WriteAsync(buffer, 0, buffer.Length);
//MPM This is the call that takes the time
await closeRequestStreamAsync(requestStream);
//response = (FtpWebResponse)request.GetResponse();
WebResponse responseWeb = await request.GetResponseAsync();
response = (FtpWebResponse)responseWeb;
if (response.StatusDescription.Contains("226"))
{
//This means that we successfully have uploaded the file!
}
response.Close();
return true;
}
catch (Exception ex)
{
string errMSG = string.Format("Upload File failed, exception: {0}", ex.Message);
//cleanUp(sourceStream, ref response, ref requestStream, ref request);
return false;
}
}
To ensure the web request, response and stream objects are closed even if an exception occurs, they should be defined in a using block.
The code can be simplified to :
var ext = Path.GetExtension(filename);
var imageExtensions=new[]{".jpg",".jpeg",".png",".gif",".bmp"};
var isimage = imageExtensions.Contains(ext);
var request = (FtpWebRequest)WebRequest.Create("ftp://someurl.com/Folder1/test1.jpg");
request.UseBinary =isimage;
request.Method = WebRequestMethods.Ftp.UploadFile;
request.ConnectionGroupName = "Group1";
request.ServicePoint.ConnectionLimit = 4;
//These are the credentials.
request.Credentials = new NetworkCredential("username", "password");
using(var sourceStream = File.OpenRead(filename))
using(var requestStream = await request.GetRequestStreamAsync())
{
await sourceStream.CopyToAsync(requestStream);
}
using(var responseWeb = await request.GetResponseAsync())
{
var response = (FtpWebResponse)responseWeb;
if (response.StatusDescription.Contains("226"))
{
return true;
}
}
.....
I removed the KeepAlive and UsePassive setters because true is their default value.
A WebRequest by itself doesn't hold any resources so it doesn't implement IDisposable. The connection to the server is made when GetRequestStream() is called. The values that need disposing/closing are sourceStream, requestStream and responseWeb.
I have problem with my C# program. I have an big zip archive (about 4Gb) which is split in small pieces, in fact each piece is 100 Mb. So, when my program start to upload files it working perfectly until 14th piece is starting uploaded. my program upload only ~90 Mb of that piece and then I receive error "The remote server returned an error: (451) Local error in processing". My C# program detect if file was not uploaded successfully and trying to upload it, so I got a never ending loop.
private static void SendToFtp(AppConfig cfg, string zipName)
{
Console.WriteLine("Starting FTP upload");
NetworkCredential creds = new NetworkCredential(cfg.FtpUserName, cfg.FtpPassword);
try
{
StringBuilder sb = new StringBuilder();
DirectoryInfo di = new DirectoryInfo(cfg.ZipFolder);
byte[] buffer = null;
foreach (var file in di.EnumerateFiles())
{
using (Stream st = File.OpenRead(file.FullName))
using (BinaryReader br = new BinaryReader(st))
{
bool success = false;
while (!success)
{
br.BaseStream.Seek(0, SeekOrigin.Begin);
buffer = br.ReadBytes((int)file.Length);
sb.Append($"ftp://{cfg.FtpHost}/{file.Name}");
request = (FtpWebRequest)WebRequest.Create(sb.ToString());
request.Method = WebRequestMethods.Ftp.UploadFile;
request.UseBinary = false;
request.UsePassive = false;
request.KeepAlive = false;
request.ServicePoint.ConnectionLimit = 1000;
request.Credentials = new NetworkCredential(cfg.FtpUserName, cfg.FtpPassword);
using (Stream requestStream = request.GetRequestStream())
{
try
{
requestStream.Write(buffer, 0, buffer.Length);
requestStream.Flush();
requestStream.Close();
var resp = (FtpWebResponse)request.GetResponse();
success = !success;
Console.WriteLine($"======================{file.Name}=======================");
Console.WriteLine($"Message:{resp.StatusDescription}");
Console.WriteLine($" Status code: {resp.StatusCode}");
Console.WriteLine($"========================================================");
}
catch (Exception ex)
{
request.Abort();
Console.WriteLine($"MSG: {ex.Message}");
}
}
sb.Clear();
}
}
}
Console.WriteLine("FTP upload finished");
}
catch (Exception ex)
{
Console.WriteLine($"{ex.Message}; {ex.Source}");
}
}
So, can someone help me or point me where I'm wrong.
Thank you!
I'm using the following code for getting an IP camera stream :
private void Display()
{
try
{
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(url);
httpRequest.Credentials = new NetworkCredential("username", "password");
HttpWebResponse myHttpWebResponse = (HttpWebResponse)httpRequest.GetResponse();
Stream receiveStream = myHttpWebResponse.GetResponseStream();
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.AppendHeader("Content-Type", "video/mp4");
using (BinaryReader binaryReader = new BinaryReader(receiveStream))
{
byte[] buffer = new byte[100000];
while (true)
{
int nbrByte = receiveStream.Read(buffer, 0, buffer.Length);
if (nbrByte == 0)
break;
Response.OutputStream.Write(buffer, 0, nbrByte);
Response.Clear();
//Response.Flush();
}
}
}
catch (Exception ex)
{
string errMsg = ex.Message;
}
}
Nothing is happening when I run the code. Using the browser and after login I can see the video. Am I missing something?
I have a C# homework, to create a download manager to download a file from an ftp server, with these conditions:
Selection of an audio file on a server.
Detection of file size.
Asynchronous transmission of the file to your work PC via ftp.
Representation of the progress of the download.
Actually, I have completed three of them, almost all, except some error occured with the second condition when I tried to get the file size before downloading, my program crashed and an error happened like this:
Error
This is the code for my downloader:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Net;
namespace DownloadDataFTP
{
public partial class ftpForm : Form
{
public ftpForm()
{
InitializeComponent();
}
private byte[] downloadedData;
//Connects to the FTP server and downloads the file
private void downloadFile(string FTPAddress, string filename, string username, string password)
{
downloadedData = new byte[0];
try
{
//Create FTP request
//Note: format is ftp://server.com/file.ext
FtpWebRequest request = FtpWebRequest.Create(FTPAddress + "/" + filename) as FtpWebRequest;
//Get the file size first (for progress bar)
request.Method = WebRequestMethods.Ftp.GetFileSize;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = true; //don't close the connection
int dataLength = (int)request.GetResponse().ContentLength;
//Now get the actual data
request = FtpWebRequest.Create(FTPAddress + "/" + filename) as FtpWebRequest;
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false; //close the connection when done
//Set up progress bar
progressBar1.Value = 0;
progressBar1.Maximum = dataLength;
lbProgress.Text = "0/" + dataLength.ToString();
//Streams
FtpWebResponse response = request.GetResponse() as FtpWebResponse;
Stream reader = response.GetResponseStream();
//Download to memory
//Note: adjust the streams here to download directly to the hard drive
MemoryStream memStream = new MemoryStream();
byte[] buffer = new byte[1024]; //downloads in chuncks
while (true)
{
Application.DoEvents(); //prevent application from crashing
//Try to read the data
int bytesRead = reader.Read(buffer, 0, buffer.Length);
if (bytesRead == 0)
{
//Nothing was read, finished downloading
progressBar1.Value = progressBar1.Maximum;
lbProgress.Text = dataLength.ToString() + "/" + dataLength.ToString();
Application.DoEvents();
break;
}
else
{
//Write the downloaded data
memStream.Write(buffer, 0, bytesRead);
//Update the progress bar
if (progressBar1.Value + bytesRead <= progressBar1.Maximum)
{
progressBar1.Value += bytesRead;
lbProgress.Text = progressBar1.Value.ToString() + "/" + dataLength.ToString();
progressBar1.Refresh();
Application.DoEvents();
}
}
}
//Convert the downloaded stream to a byte array
downloadedData = memStream.ToArray();
//Clean up
reader.Close();
memStream.Close();
response.Close();
MessageBox.Show("Downloaded Successfully");
}
catch (Exception)
{
MessageBox.Show("There was an error connecting to the FTP Server.");
}
txtData.Text = downloadedData.Length.ToString();
this.Text = "Download and Upload Data through FTP";
username = string.Empty;
password = string.Empty;
}
//Upload file via FTP
private void Upload(string FTPAddress, string filePath, string username, string password)
{
//Create FTP request
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(FTPAddress + "/" + Path.GetFileName(filePath));
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
//Load the file
FileStream stream = File.OpenRead(filePath);
byte[] buffer = new byte[stream.Length];
stream.Read(buffer, 0, buffer.Length);
stream.Close();
//Upload file
Stream reqStream = request.GetRequestStream();
reqStream.Write(buffer, 0, buffer.Length);
reqStream.Close();
MessageBox.Show("Uploaded Successfully");
}
//get file size for downloading
private void FileSize_down(string FTPAddress, string filename)
{
FtpWebRequest request = FtpWebRequest.Create(FTPAddress + "/" + filename) as FtpWebRequest;
request.Method = WebRequestMethods.Ftp.GetFileSize;
long dataLength = (long)request.GetResponse().ContentLength;
sizeFile.Text = dataLength.ToString();
}
//get file size for uploading
private void FileSize_up(string filename)
{
if (UpFile.Text != "")
{
//direction file
FileInfo f = new FileInfo(UpFile.Text);
//add size to text box
textBox1.Text = f.Length.ToString();
}
else
MessageBox.Show("Choose file to upload");
}
//Connects to the FTP server and request the list of available files
private void getFileList(string FTPAddress, string username, string password)
{
List<string> files = new List<string>();
try
{
//Create FTP request
FtpWebRequest request = FtpWebRequest.Create(FTPAddress) as FtpWebRequest;
request.Method = WebRequestMethods.Ftp.ListDirectory;
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
FtpWebResponse response = request.GetResponse() as FtpWebResponse;
Stream responseStream = response.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
while (!reader.EndOfStream)
{
Application.DoEvents();
files.Add(reader.ReadLine());
}
//Clean-up
reader.Close();
responseStream.Close(); //redundant
response.Close();
}
catch (Exception)
{
MessageBox.Show("There was an error connecting to the FTP Server");
}
username = string.Empty;
password = string.Empty;
this.Text = "Download and Upload Data through FTP"; //Back to normal title
//If the list was successfully received, display it to the user
//through a dialog
if (files.Count != 0)
{
listDialogForm dialog = new listDialogForm(files);
if (dialog.ShowDialog() == DialogResult.OK)
{
//Update the File Name field
txtFileName.Text = dialog.ChosenFile;
}
}
}
//Make sure the FTP server address has ftp:// at the beginning
private void txtFTPAddress_Leave(object sender, EventArgs e)
{
if (!txtFTPAddress.Text.StartsWith("ftp://"))
txtFTPAddress.Text = "ftp://" + txtFTPAddress.Text;
}
This is the part that gets file size for download.
//get file size for downloading
private void FileSize_down(string FTPAddress, string filename)
{
FtpWebRequest request = FtpWebRequest.Create(FTPAddress + "/" + filename) as FtpWebRequest;
request.Method = WebRequestMethods.Ftp.GetFileSize;
long dataLength = (long)request.GetResponse().ContentLength;
sizeFile.Text = dataLength.ToString();
}
Thanks so much!
You are getting a 530 (not logged in) error. Seems like that is the issue. In your other methods(downloadFile, getFileList, etc) you include:
request.Credentials = new NetworkCredential(username, password);
request.UsePassive = true;
request.UseBinary = true;
request.KeepAlive = false;
in your Filesize_down you do not.
How do you copy a file on an FTP server? My goal is to copy ftp://www.mysite.com/test.jpg to ftp://www.mysite.com/testcopy.jpg. To rename a file, I would use:
var request = (FtpWebRequest)WebRequest.Create("ftp://www.mysite.com/test.jpg");
request.Credentials = new NetworkCredential(user, pass);
request.Method = WebRequestMethods.Ftp.Rename;
request.RenameTo = "testrename.jpg"
request.GetResponse().Close();
FtpWebResponse resp = (FtpWebResponse)request.GetResponse();
However, there is no Method for copying files. How would you do copy a file?
Try this:
static void Main(string[] args)
{
CopyFile("countrylist.csv", "MySample.csv", "username", "password#");
}
public static bool CopyFile(string fileName, string FileToCopy, string userName, string password)
{
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftp.mysite.net/" + fileName);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential(userName, password);
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
Stream responseStream = response.GetResponseStream();
Upload("ftp://ftp.mysite.net/" + FileToCopy, ToByteArray(responseStream), userName, password);
responseStream.Close();
return true;
}
catch
{
return false;
}
}
public static Byte[] ToByteArray(Stream stream)
{
MemoryStream ms = new MemoryStream();
byte[] chunk = new byte[4096];
int bytesRead;
while ((bytesRead = stream.Read(chunk, 0, chunk.Length)) > 0)
{
ms.Write(chunk, 0, bytesRead);
}
return ms.ToArray();
}
public static bool Upload(string FileName, byte[] Image, string FtpUsername, string FtpPassword)
{
try
{
System.Net.FtpWebRequest clsRequest = (System.Net.FtpWebRequest)System.Net.WebRequest.Create(FileName);
clsRequest.Credentials = new System.Net.NetworkCredential(FtpUsername, FtpPassword);
clsRequest.Method = System.Net.WebRequestMethods.Ftp.UploadFile;
System.IO.Stream clsStream = clsRequest.GetRequestStream();
clsStream.Write(Image, 0, Image.Length);
clsStream.Close();
clsStream.Dispose();
return true;
}
catch
{
return false;
}
}
This downloads the file to a stream, and then uploads it.
FtpWebRequest is a lightweight class. Microsoft felt it should be used by simple client to download and delete the files once the client is finish.
I guess you can't really do this with FTP. What you can do is download the file you want to copy and then upload it with a new name. For example:
try
{
WebClient request = new WebClient();
request.Credentials = new NetworkCredential(user, pass);
byte[] data = request.DownloadData(host);
MemoryStream file = new MemoryStream(data);
Upload(data);
}
catch (Exception ex)
{
}
...
private void Upload(byte[] buffer)
{
try
{
FtpWebRequest request = (FtpWebRequest)FtpWebRequest.Create(newname);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential(user, pass);
Stream reqStream = request.GetRequestStream();
reqStream.Write(buffer, 0, buffer.Length);
reqStream.Close();
var resp = (FtpWebResponse)request.GetResponse();
}
catch (Exception ex)
{
}
}
In our project we did someting like this
// pass parameters according to your need,
// the below code is done in a hard coded manner for clarity
public void Copy()
{
// from where you want to copy
var downloadRequest = (FtpWebRequest)WebRequest.Create("ftp://www.mysite.com/test.jpg");
downloadRequest.Credentials = new NetworkCredential("userName", "passWord");
downloadRequest.Method = WebRequestMethods.Ftp.DownloadFile;
var ftpWebResponse = (FtpWebResponse)downloadRequest.GetResponse();
var downloadResponse = ftpWebResponse.GetResponseStream();
int buffLength = 2048;
byte[] byteBuffer = new byte[buffLength];
// bytes read from download stream.
// from documentation: When overridden in a derived class, reads a sequence of bytes from the
// current stream and advances the position within the stream by the number of bytes read.
int bytesRead = downloadResponse.Read(byteBuffer, 0, buffLength);
// the place where you want the file to go
var uploadRequest = (FtpWebRequest)WebRequest.Create("ftp://www.mysite.com/testCopy.jpg");
uploadRequest.Credentials = new NetworkCredential("userName", "passWord");
uploadRequest.Method = WebRequestMethods.Ftp.UploadFile;
var uploadStream = uploadRequest.GetRequestStream();
if (bytesRead > 0)
{
while (bytesRead > 0)
{
uploadStream.Write(byteBuffer, 0, bytesRead);
bytesRead = downloadResponse.Read(byteBuffer, 0, buffLength);
}
}
uploadStream.Close();
uploadStream.Dispose();
downloadResponse.Close();
ftpWebResponse.Close();
((IDisposable)ftpWebResponse).Dispose();
}