FTP in C# in a WinForms app times out - c#

I have an FTP server from which I pull and parse data and download images. I've never had an issue pulling text files (my data) but there are 2 directories that I pull images from and one works without a hitch using code identical to below (though obviously with a different Uri and image name array). In order to get a list of the images I have a function which pulls another file and returns an array of the image names and then I put this array of image names sequentially on the end of a base URI in a loop to download all images.
The code at the bottom is my function for pulling the text file with the image names. It has it's own URI and comes from a different part of the directory structure. The interesting thing is that if I manually create an array of images in a known location and feed my image pull code, it works fine but if I run this array building FTP function my image pulls timeout in the GetResponse() line. I've shortened the timeout so I don't have to wait so long for it to fail but it's not too short since as I said it works fine with a hard coded list of image URIs. I've searched here and tried several things thinking I wasn't releasing resources correctly but I cannot figure out what's happening.
Sorry I'm not an expert at this but I have lots of similar code in this app and this is the first time I've had trouble with FTPing.
One note, I have an earlier version of this app which works fine but I must admit I have been very lax in my source version control and don't have the old code (doh!). I changed something that is now killing it.
//Open a web request based on the URI just built from user selections
FtpWebRequest imageRequest = (FtpWebRequest)WebRequest.Create(imageUri);
imageRequest.UsePassive = false;
imageRequest.UseBinary = true;
imageRequest.KeepAlive = false;
imageRequest.Timeout = 2000;
//Act on that webrequest based on what the user wants to do (i.e. list a directory, list file, download, etc)
imageRequest.Method = WebRequestMethods.Ftp.DownloadFile;
try
{
//Now get the response from the tool as a stream.
FtpWebResponse imageResponse = (FtpWebResponse)imageRequest.GetResponse();
//Thread.Sleep(1000);
Stream imageResponseStream = imageResponse.GetResponseStream();
byte[] buffer = new byte[2048];
FileStream fs = new FileStream(newPath + #"\" + templateImageArray2[x].Split(' ')[0], FileMode.Create);
int ReadCount = imageResponseStream.Read(buffer, 0, buffer.Length);
while (ReadCount > 0)
{
fs.Write(buffer, 0, ReadCount);
ReadCount = imageResponseStream.Read(buffer, 0, buffer.Length);
}
fs.Close();
imageResponseStream.Close();
}
catch (WebException r)
{
if (r.Status == WebExceptionStatus.Timeout)
{
//Obtain more detail on error:
var response = (FtpWebResponse)r.Response;
FtpStatusCode errorCode = response.StatusCode;
string errorMessage = response.StatusDescription;
MessageBox.Show(errorMessage);
//goto RETRY;
}
MessageBox.Show(r.Message);
break;
}
string[] tempIDPText = new string[0];
Uri fileUriLocal = new Uri("ftp://srvrname:password#" + tempIpAddress + "/%2fROOT/DEVICE/HD/" + comboClass.Text + "/data/" + dirName1 + "/" + dirName2 + ".img");
//Open a web request based on the URI just built from user selections
FtpWebRequest requestLocal = (FtpWebRequest)WebRequest.Create(fileUriLocal);
requestLocal.UsePassive = false;
requestLocal.UseBinary = true;
requestLocal.KeepAlive = false;
//Act on that webrequest based on what the user wants to do (i.e. list a directory, list file, download, etc)
requestLocal.Method = WebRequestMethods.Ftp.DownloadFile;
try
{
//Now get the response from the tool as a stream.
FtpWebResponse responseLocal = (FtpWebResponse)requestLocal.GetResponse();
Stream responseStream = responseLocal.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
//Now read an individual file and fill the array with the chamber status
int y = 0;
while (!reader.EndOfStream)
{
if (reader.EndOfStream)
break;
else
{
Array.Resize(ref tempIDPText, tempIDPText.Length + 1);
tempIDPText[tempIDPText.Length - 1] = reader.ReadLine();
}
}
reader.Close();
responseStream.Close();
responseLocal.Close();
ServicePoint srvrPoint = ServicePointManager.FindServicePoint(fileUriLocal);
MethodInfo ReleaseConns = srvrPoint.GetType().GetMethod
("ReleaseAllConnectionGroups",
BindingFlags.Instance | BindingFlags.NonPublic);
ReleaseConns.Invoke(srvrPoint, null);
}
catch (WebException r)
{
//Obtain more detail on the error;
var response = (FtpWebResponse)r.Response;
FtpStatusCode errorCode = response.StatusCode;
string errorMessage = response.StatusDescription;
MessageBox.Show(errorCode.ToString());
MessageBox.Show("When getting file Dates: " + errorMessage.ToString());
}
return tempIDPText;

Related

Unable to download the PDF file from URL

I need to download an .PDF file from a website : https://XXXXX/XXXX/XXXXXXX.pdf when user click's on link button. Below code is working fine in local but when I try to click on link button for downloading the file after deploying into server, First time it is working fire but next consecutive downloads, It is displaying as The XXXX.PDF download was interrupted or file cannot be downloaded.
try
{
string fullFileName =string.Empty;
LinkButton btn = (LinkButton)(sender);
string filepath = btn.CommandArgument;
string fileName = btn.Text;
if (fileName != null && !string.IsNullOrEmpty(fileName))
{
fullFileName = filePath +fileName ;
int bytesToRead = 10000;
// Buffer to read bytes in chunk size specified above
byte[] buffer = new Byte[bytesToRead];
//string fileName = System.IO.Path.GetFileName(fullFileName);
//Create a WebRequest to get the file
System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | System.Net.SecurityProtocolType.Tls | (SecurityProtocolType)768/*TLS1.1*/ | (SecurityProtocolType)3072/*TLS1.2*/;
HttpWebRequest fileReq = (HttpWebRequest)HttpWebRequest.Create(fullFileName);
//Create a response for this request
HttpWebResponse fileResp = (HttpWebResponse)fileReq.GetResponse();
if (fileReq.ContentLength > 0)
fileResp.ContentLength = fileReq.ContentLength;
//Get the Stream returned from the response
stream = fileResp.GetResponseStream();
// prepare the response to the client. resp is the client Response
var resp = HttpContext.Current.Response;
//Indicate the type of data being sent
resp.ContentType = "application/PDF";
//Name the file
resp.AddHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
resp.AddHeader("Content-Length", fileResp.ContentLength.ToString());
int length;
do
{
// Verify that the client is connected.
if (resp.IsClientConnected)
{
// Read data into the buffer.
length = stream.Read(buffer, 0, bytesToRead);
// and write it out to the response's output stream
resp.OutputStream.Write(buffer, 0, length);
// Flush the data
resp.Flush();
//Clear the buffer
buffer = new Byte[bytesToRead];
}
else
{
// cancel the download if client has disconnected
length = -1;
}
} while (length > 0); //Repeat until no data is read
}
else
{
lblFile.Text = "File Name is missing";
lblFile.Visible = true;
}
}
catch (Exception ex)
{
}
finally
{
if (stream != null)
{
//Close the input stream
stream.Close();
}
}
Can someone please guide me why it is failing in server

Request stream fail to write

I have to upload a large file to the server with the following code snippet:
static async Task LordNoBugAsync(string token, string filePath, string uri)
{
HttpWebRequest fileWebRequest = (HttpWebRequest)WebRequest.Create(uri);
fileWebRequest.Method = "PATCH";
fileWebRequest.AllowWriteStreamBuffering = false; //this line tells to upload by chunks
fileWebRequest.ContentType = "application/x-www-form-urlencoded";
fileWebRequest.Headers["Authorization"] = "PHOENIX-TOKEN " + token;
fileWebRequest.KeepAlive = false;
fileWebRequest.Timeout = System.Threading.Timeout.Infinite;
fileWebRequest.Proxy = null;
using (FileStream fileStream = File.OpenRead(filePath) )
{
fileWebRequest.ContentLength = fileStream.Length; //have to provide length in order to upload by chunks
int bufferSize = 512000;
byte[] buffer = new byte[bufferSize];
int lastBytesRead = 0;
int byteCount = 0;
Stream requestStream = fileWebRequest.GetRequestStream();
requestStream.WriteTimeout = System.Threading.Timeout.Infinite;
while ((lastBytesRead = fileStream.Read(buffer, 0, bufferSize)) != 0)
{
if (lastBytesRead > 0)
{
await requestStream.WriteAsync(buffer, 0, lastBytesRead);
//for some reasons didnt really write to stream, but in fact buffer has content, >60MB
byteCount += bufferSize;
}
}
requestStream.Flush();
try
{
requestStream.Close();
requestStream.Dispose();
}
catch
{
Console.Write("Error");
}
try
{
fileStream.Close();
fileStream.Dispose();
}
catch
{
Console.Write("Error");
}
}
...getting response parts...
}
In the code, I made a HttpWebRequest and push the content to server with buffering. The code works perfectly for any files under 60MB.
I tried a 70MB pdf. The buffer array has different content for each buffering. Yet, the request stream does not seem to be getting written. The bytecount also reached 70M, showing the file is properly read.
Edit (more info): I set the break point at requestStream.Close(). It clearly takes ~2 mins for the request stream to write in 60MB files but only takes 2ms for 70MB files.
My calling:
Task magic = LordNoBugAsync(token, nameofFile, path);
magic.Wait();
I am sure my calling is correct (it works for 0B to 60MB files).
Any advice or suggestion is much appreciated.

HttpListener return audio file so it plays on browser

I am using the HttpListener class to create a very simple web server.
I am able to serve html, javascript, attachements probably everything to the browser. The only thing I am having trouble is giving the browser a wav file so that it plays it.
The file that I want to play in the browser is this one:
https://dl.dropboxusercontent.com/u/81397375/a.wav
Note how if you click on that link your browser starts playing the audio file instead of downloading it as an attachment. I want to do the same thing with the HttpListerner class!
Anyways here is my code:
string pathToMyAudioFile = #"c:\a.wav";
// create web server
var web = new HttpListener();
// listen on port 8081 only on local connections for testing purposes
web.Prefixes.Add("http://localhost:8081/");
Console.WriteLine(#"Listening...");
web.Start();
// run web server forever
while (true)
{
var context = web.GetContext();
var requestUrl = context.Request.Url.LocalPath.Trim('/');
// this command will stop the web server
if (requestUrl == "Stop")
{
context.Response.StatusCode = 200; // set response to ok
context.Response.OutputStream.Close();
break;
}
else if (requestUrl == "DownloadAudio") // <--------- here is where I am interested
{
// we are ready to give audio file to browser
using (var fs = new FileStream(pathToMyAudioFile , FileMode.Open))
{
context.Response.ContentLength64 = fs.Length;
context.Response.SendChunked = true;
//obj.Response.ContentType = System.Net.Mime.MediaTypeNames.Application.Octet;
context.Response.ContentType = "audio/wav";
//obj.Response.AddHeader("Content-disposition", "attachment; filename=" + fs.Name);
context.Response.StatusCode = 206; // set to partial content
byte[] buffer = new byte[64 * 1024];
try
{
using (BinaryWriter bw = new BinaryWriter(context.Response.OutputStream))
{
int read;
while ((read = fs.Read(buffer, 0, buffer.Length)) > 0)
{
bw.Write(buffer, 0, read);
bw.Flush(); //seems to have no effect
}
bw.Close();
}
}
catch
{
Console.Write("closded connection");
}
}
}
else
{
context.Response.StatusCode = 404; // set response to not found
}
// close output stream
context.Response.OutputStream.Close();
}
web.Stop();
Now when I go to http://localhost:8081/DownloadAudio I see this:
But I am not able to play the file. Why? What headers am I missing? I do not want to download the file as an attachment.
Solution
I just found the solution. I was missing the Content-Range header. This how the response looks when making it agains a real web server IIS:
Note how it specifies the ranges it sends with the header: Content-Range: bytes 0-491515/491516
So I just have to add the line
context.Response.Headers.Add("Content-Range", $"bytes 0-{fs.Length-1}/{fs.Length}");
To my code and now it works! If the audio file is very large I could do some math so I do not return everything at once.

IIS7 buffer size limit

My problem happens when trying to download a video file via http request
in the following operating systems using IIS7:
win2008 32Bit, Win2008 R2 64Bit
Currently works fine on: win2003 , vista64 (IIS6)
Problem description:
When users request a file larger than 256mb via C# they get a limited file, even when
using Content-Length param it seems that the file get the right size but not the full
content.
When requesting the URL of the file, I get the full file, the problem occurs only via
the C# script, also the C# response that the full buffer was sent to the user.
I've changed the IIS7 settings in the article:
http://blog.twinharbor.com/2011/07/28/fixing-iis7-maximum-upload-size/
and still it doesn't work.
Also, there are no remarks or errors anywhere.
Please find a sample of my code:
var context = System.Web.HttpContext.Current;
context.Response.ContentEncoding = Encoding.GetEncoding("windows-1255");
context.Response.HeaderEncoding = Encoding.GetEncoding("UTF-8");
context.Response.Charset = "utf-8";
System.IO.Stream iStream = null;
// Buffer to read 100K bytes in chunk:
byte[] buffer = new Byte[100000];
// Length of the file:
int length=0;
// Total bytes to read:
long dataToRead=0;
// Identify the file to download including its path.
string filepath = u.Trim(BigFile);
// Identify the file name.
string filename = System.IO.Path.GetFileName(filepath);
Start.Value = u.Time();
try
{
iStream = new System.IO.FileStream(filepath, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);
dataToRead = iStream.Length;
context.Response.Charset = "";
context.Response.ContentType = "application/octet-stream";
context.Response.AddHeader("Content-Disposition", "attachment; filename=" + filename);
context.Response.AddHeader("Content-Length", dataToRead.ToString());
while (dataToRead > 0)
{
if (context.Response.IsClientConnected)
{
length = iStream.Read(buffer, 0, 100000);
context.Response.OutputStream.Write(buffer, 0, length);
context.Response.Flush();
buffer = new Byte[100000];
dataToRead = dataToRead - length;
}
else
{
dataToRead = -1;
}
}
}
catch (Exception ex)
{
context.Response.Write("Error : " + ex.Message);
}
finally
{
if (iStream != null)
{
iStream.Close();
}
context.Response.Close();
}
I'll appericiate your help.
Thanks.

Program hangs on FtpWebResponse

First time poster, long-time reader. I have a really annoying problem thats been getting on my nerves. Ive got a program set up so I listen for new files on an FTP server, if theres a new file I download it. From there I work on some of the information in the file, etc. My problem comes when I run through my sequence the second time. That is, on the first file I download everything is totally fine, but as soon as a new file gets detected and my program tries downloading it, my program just hangs.
private static void DownloadFile(string s)
{
try
{
FtpWebRequest request = (FtpWebRequest)WebRequest.Create("ftp://blabla.com/"+s);
request.Method = WebRequestMethods.Ftp.DownloadFile;
request.Credentials = new NetworkCredential("xxx" ,"zzz");
using (FtpWebResponse partResponse = (FtpWebResponse)request.GetResponse())
{
Stream partReader = partResponse.GetResponseStream();
byte[] buffer = new byte[1024];
FileInfo fi = new FileInfo(path);
FileStream memStream = fi.Create();
while (true)
{
int bytesRead = partReader.Read(buffer, 0, buffer.Length - 1);
if (bytesRead == 0)
break;
memStream.Write(buffer, 0, bytesRead);
}
partResponse.Close();
memStream.Close();
}
Console.WriteLine(DateTime.Now + " file downloaded");
MoveFileToInProgress(s);
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
The line it hangs on is this one:
using (FtpWebResponse partResponse = (FtpWebResponse)request.GetResponse())
The reason my method here is static is because Im just running it in a different project to test it.. My question here is, how come it only ever dies on the second file? Ive been staring myself blind for hours now!
I ran into this problem as well... try finishing your request first and then closing it before trying to retrieve the response. That worked for me (actually tried it after reading comment by MartinNielsen). Here is what I did.
// connect to the ftp site
FtpWebRequest ftpRequest = (FtpWebRequest)WebRequest.Create(ftpUri);
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile;
ftpRequest.Credentials = new NetworkCredential(ftpUser, ftpPassword);
// setting proxy to null so that it does not go through the proxy
ftpRequest.Proxy = null;
// get file information
StreamReader fileStream = new StreamReader(filePath);
byte[] fileBytes = Encoding.UTF8.GetBytes(fileStream.ReadToEnd());
ftpRequest.ContentLength = fileBytes.Length;
fileStream.Close();
// open connection to ftp site
Stream ftpRequestStream = ftpRequest.GetRequestStream();
// write the file to the stream
ftpRequestStream.Write(fileBytes, 0, fileBytes.Length);
// close the stream
ftpRequestStream.Close();
// get the response from the server
FtpWebResponse ftpUploadResponse = (FtpWebResponse)ftpRequest.GetResponse();
string result = ftpUploadResponse.StatusDescription;
// close response
ftpUploadResponse.Close();
// return response to calling code
return result;
Here are a couple of the resources that I used when writing this code (won't let me post more than 2, there were more)
How to: Upload Files with FTP
Uploading a file -- "The requested URI is invalid for this FTP command"
I'm not expert on C# but I use this code to download files from my ftp:
public void Download(string filename)
{
// I try to download five times before crash
for (int i = 1; i < 5; i++)
{
try
{
FtpWebRequest ftp = (FtpWebRequest)FtpWebRequest.Create(Global.Path + "/" + filename);
ftp.Credentials = new NetworkCredential(User, Pass);
ftp.KeepAlive = false;
ftp.Method = WebRequestMethods.Ftp.DownloadFile;
ftp.UseBinary = true;
ftp.Proxy = null;
int buffLength = 2048;
byte[] buff = new byte[buffLength];
int contentLen;
string LocalDirectory = Application.StartupPath.ToString() + "/downloads/" + filename;
using (FileStream fs = new FileStream(LocalDirectory, FileMode.Create, FileAccess.Write, FileShare.None))
using (Stream strm = ftp.GetResponse().GetResponseStream())
{
contentLen = strm.Read(buff, 0, buffLength);
while (contentLen != 0)
{
fs.Write(buff, 0, contentLen);
contentLen = strm.Read(buff, 0, buffLength);
}
}
Process.Start(LocalDirectory);
break;
}
catch (Exception exc)
{
if (i == 5)
{
MessageBox.Show("Can't download, try number: " + i + "/5 \n\n Error: " + exc.Message,
"Problem downloading the file");
}
}
}
}
Tell me if it works for you :)

Categories