C# FTP upload stuck on particular file - c#

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!

Related

download file on client-side sent in response of API

I have a task to download whatever file is sent in the response of my API call, Possible extensions are zip, pdf and doc. I just have the API endpoints to download those files returned in the response, no idea about server side code.
The task is not to write or create those files on server and then transmit to local, but need to download it directly on the client side.
I have written a web method which calls the API on click of button and gets the response stream, the code written also downloads the required file correctly , but those downloaded files never open. they are either corrupted or damaged.
Below is my code to download and write the file on client side.
Any idea what is possibly going wrong, or how can i download the files correctly.
Note: This aren't very large files, the max size possibly could be 50Mb or so.
Not sure, what all things from stack overflow i have tried so far, but no luck was for sure.
public string CallService(string hbno)
{
try
{
var httpWebRequest = (HttpWebRequest)WebRequest.Create("URL");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
DataTable dt = GetPrintLogData(hbno);
if (dt != null && dt.Rows.Count > 0)
{
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = _Serializer.Serialize(body);
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
using (var resp = (HttpWebResponse)httpWebRequest.GetResponse())
{
using (var stream = resp.GetResponseStream())
{
if (resp.StatusCode == HttpStatusCode.OK)
{
var cd = new ContentDisposition(resp.Headers["Content-Disposition"]);
StreamToFileAttachment(stream, cd.FileName);
return "successful";
}
else
{
return "Something went wrong";
}
}
}
}
else { return "No match found in database"; }
}
catch (Exception ex)
{
throw;
}
}
public static byte[] ReadFully2(Stream stream)
{
try
{
byte[] buffer = new byte[32768]; //set the size of your buffer (chunk)
using (MemoryStream ms = new MemoryStream()) //You need a db connection instead
{
while (true) //loop to the end of the file
{
int read = stream.Read(buffer, 0, buffer.Length); //read each chunk
if (read <= 0)
{
var test = ms.ToArray().Length;
//check for end of file
return ms.ToArray();
}
else
{
ms.Write(buffer, 0, read); //write chunk to [wherever]
}
}
}
}
catch (Exception ex)
{
//throw;
}
}
static void StreamToFileAttachment(Stream str, string fileName)
{
try
{
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
var length = ReadFully2(str).Length;
byte[] buf = new byte[length]; //declare arraysize
str.Read(buf, 0, buf.Length);
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + fileName);
HttpContext.Current.Response.AddHeader("Content-Length", length.ToString());
HttpContext.Current.Response.ContentType = GetMimeTypeByFileName(fileName);
HttpContext.Current.Response.OutputStream.Write(buf, 0, buf.Length);
HttpContext.Current.Response.Flush(); // Sends all currently buffered output to the client.
HttpContext.Current.Response.SuppressContent = true; // Gets or sets a value indicating whether to send HTTP content to the client.
HttpContext.Current.ApplicationInstance.CompleteRequest(); // Causes ASP.NET to bypass all events and filtering in the HTTP pipeline chain of execution and directly execute the EndRequest event.
// HttpContext.Current.Response.End();
}
catch (Exception ex)
{
//throw;
}
}

FtpWebRequest GetRequestStream() gots time-outed at second call

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();
}

Upload Multiple files to FTP in c#

i'm using the below method to upload files from local server to FTP server, here i'm creating a new connection and initiating a new session each and every file uploading and closing the same. how to achieve this in single initiated session in c#.
this is my code
public bool UploadTempFilesToFTP()
{
string[] fileList;
try
{
ConfiguredValues conObj = new ConfiguredValues();
conObj.PickTheValuesFromConfigFile();
fileList = Directory.GetFiles(conObj.tempPath);
foreach (string FileName in fileList)
{
FtpWebRequest upldrequest = (FtpWebRequest)FtpWebRequest.Create(conObj.tempOutboundURL + FileName);
upldrequest.UseBinary = true;
upldrequest.KeepAlive = false;
upldrequest.Timeout = -1;
upldrequest.UsePassive = true;
upldrequest.Credentials = new NetworkCredential(conObj.user, conObj.pass);
upldrequest.Method = WebRequestMethods.Ftp.UploadFile;
string destinationAddress = conObj.tempPath;
FileStream fs = File.OpenRead(destinationAddress + FileName);
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
fs.Close();
Stream requestStr = upldrequest.GetRequestStream();
requestStr.Write(buffer, 0, buffer.Length);
requestStr.Close();
requestStr.Flush();
FtpWebResponse response = (FtpWebResponse)upldrequest.GetResponse();
response.Close();
File.Delete(destinationAddress + FileName);
}
Console.WriteLine("Uploaded Successfully to Temp folder");
return true;
}
catch (Exception ex)
{
Console.WriteLine("Upload failed. {0}", ex.Message);
return false;
}
}
it's weird that i answer an old question but i try almost everything to upload multiple files to ftp with no luck while the solution is very simple and effective, using LOOPING - foreach solved the issue for me i use the below function to Upload the files in one simple step..
public void Uploadbulkftpfiles(string[] list)
{
bool ife;// is folder exists
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://ftpsite.com/folder");
request.Credentials = new NetworkCredential("Username", "Password");
request.Method = WebRequestMethods.Ftp.ListDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
ife = true;
}
catch (Exception)
{
ife = false;
}
/////////////////////////////////////////////begin of upload process
if (ife)//the folder is already exists
{
foreach (var str in list)
{
try
{
FtpWebRequest requestUP2 = (FtpWebRequest)WebRequest.Create("ftp://ftpsite.com/folder" + str);
requestUP2.Credentials = new NetworkCredential("UserName", "Password");
requestUP2.Method = WebRequestMethods.Ftp.UploadFile;
requestUP2.KeepAlive = false;
requestUP2.UsePassive = true;
using (Stream fileStream = File.OpenRead("ftp://ftpsite.com/folder" + str))
using (Stream ftpStream = requestUP2.GetRequestStream())
{
fileStream.CopyTo(ftpStream);
}
}
catch (Exception ex1)
{
MessageBox.Show(ex1.Message);
}
}
}
else if (!ife)
{
//CREATE THE FOLDER
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp:ftpsite/folder");
request.Credentials = new NetworkCredential("UserName", "Password");
request.Method = WebRequestMethods.Ftp.MakeDirectory;
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
}
catch (Exception excr) { MessageBox.Show(excr.Message); }
//UPLOAD THE FILES
foreach (var str in list)
{
try
{
FtpWebRequest requestUP2 = (FtpWebRequest)WebRequest.Create("ftp://ftpsite.com/folder" + str);
requestUP2.Credentials = new NetworkCredential("UserName", "Password");
requestUP2.Method = WebRequestMethods.Ftp.UploadFile;
requestUP2.KeepAlive = false;
requestUP2.UsePassive = true;
using (Stream fileStream = File.OpenRead("ftp://ftpsite.com/folder" + str))
using (Stream ftpStream = requestUP2.GetRequestStream())
{
fileStream.CopyTo(ftpStream);
}
}
catch (Exception ex1)
{
MessageBox.Show(ex1.Message);
}
}
}
}
The ftp protocol is intended to works on request basis.
You start a request with a method (in your case UploadFile).
The only thing you can do is to KeepAlive your request to avoid connection closing
upldrequest.KeepAlive = true;
on every request you create except the last one. This will make a login only the first FTPWebRequest.
Then when you create the last FTPWebRequest, set
upldrequest.KeepAlive = false;
and it will close the connection when done.

Uploading files to FTP are corrupted once in destination

I'm creating a simple drag-file-and-upload-automatically-to-ftp windows application
and I'm using the MSDN code to upload the file to the FTP.
The code is pretty straight forward:
// Get the object used to communicate with the server.
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(String.Format("{0}{1}", FTP_PATH, filenameToUpload));
request.Method = WebRequestMethods.Ftp.UploadFile;
// Options
request.UseBinary = true;
request.UsePassive = false;
// FTP Credentials
request.Credentials = new NetworkCredential(FTP_USR, FTP_PWD);
// Copy the contents of the file to the request stream.
StreamReader sourceStream = new StreamReader(fileToUpload.FullName);
byte[] fileContents = Encoding.UTF8.GetBytes(sourceStream.ReadToEnd());
sourceStream.Close();
request.ContentLength = fileContents.Length;
Stream requestStream = request.GetRequestStream();
requestStream.Write(fileContents, 0, fileContents.Length);
requestStream.Close();
FtpWebResponse response = (FtpWebResponse)request.GetResponse();
writeOutput("Upload File Complete!");
writeOutput("Status: " + response.StatusDescription);
response.Close();
and it does get uploaded to the FTP
Problem is when I see the file on a browser, or simply download and try to see it on desktop I get:
I already used request.UseBinary = false; and request.UsePassive = false; but it does not seam to do any kind of good whatsoever.
What I have found out was that, the original file has 122Kb lenght and in the FTP (and after downloading), it has 219Kb...
What am I doing wrong?
By the way, the uploadFileToFTP() method is running inside a BackgroundWorker, but I don't really thing that makes any difference...
You shouldn't use a StreamReader but only a Stream to read binary files.
Streamreader is designed to read text files only.
Try with this :
private static void up(string sourceFile, string targetFile)
{
try
{
string ftpServerIP = ConfigurationManager.AppSettings["ftpIP"];
string ftpUserID = ConfigurationManager.AppSettings["ftpUser"];
string ftpPassword = ConfigurationManager.AppSettings["ftpPass"];
////string ftpURI = "";
string filename = "ftp://" + ftpServerIP + "//" + targetFile;
FtpWebRequest ftpReq = (FtpWebRequest)WebRequest.Create(filename);
ftpReq.UseBinary = true;
ftpReq.Method = WebRequestMethods.Ftp.UploadFile;
ftpReq.Credentials = new NetworkCredential(ftpUserID, ftpPassword);
byte[] b = File.ReadAllBytes(sourceFile);
ftpReq.ContentLength = b.Length;
using (Stream s = ftpReq.GetRequestStream())
{
s.Write(b, 0, b.Length);
}
FtpWebResponse ftpResp = (FtpWebResponse)ftpReq.GetResponse();
if (ftpResp != null)
{
MessageBox.Show(ftpResp.StatusDescription);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
The problems are caused by your code decoding the binary data to character data and back to binary data. Don't do this.
Use the UploadFile Method of the WebClient Class:
using (WebClient client = new WebClient())
{
client.Credentials = new NetworkCredential(FTP_USR, FTP_PWD);
client.UploadFile(FTP_PATH + filenameToUpload, filenameToUpload);
}

FtpWebRequest closing the upload stream hangs on large files

I am trying to use an FtpWebRequest to upload some files. This works for smallish files (say <2MB), but when I am trying to load a 16MB file, the files uploads successfully, but when I call request.GetRequestStream().Close, the code hangs (or timesout if the timeout is low enough).
I could just a) not close it and b)not bother to get the response from the server, but that doesn't seem right! See code below (using SSL or not, the same problem occurs.)
output.Close() is the line that hangs....
public static void SendFileViaFtp(string file, string url, bool useSsl, ICredentials credentials)
{
var request = (FtpWebRequest)WebRequest.Create(url + Path.GetFileName(file));
request.EnableSsl = useSsl;
request.UseBinary = true;
request.Credentials = credentials;
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Timeout = 10000000;
request.ReadWriteTimeout = 10000000;
request.KeepAlive = true;
var input = File.Open(file, FileMode.Open);
var output = request.GetRequestStream();
var buffer = new byte[1024];
var lastBytesRead = -1;
var i = 0;
while (lastBytesRead != 0)
{
i++;
lastBytesRead = input.Read(buffer, 0, 1024);
Debug.WriteLine(lastBytesRead + " " + i);
if (lastBytesRead > 0)
{
output.Write(buffer, 0, lastBytesRead);
}else
{
Debug.WriteLine("Finished");
}
}
input.Close();
output.Close();
var response = (FtpWebResponse)request.GetResponse();
response.Close();
}
Thanks,
try
// after finished uploading
request.Abort(); // <=== MAGIC PART
// befor response.Close()
var response = (FtpWebResponse)request.GetResponse();
response.Close();
taken from here
try to close output before input.
make sure the last buffer isn't to large, or you could write a few empty bytes.
I don't know if it's necessary but i always set the request contentlength to the inputfile-length.
Here is an good example: http://dotnet-snippets.de/dns/ftp-file-upload-mit-buffer-SID886.aspx

Categories

Resources